I'm using xslt module to query BaseX.
<query><text>
let $xml := doc("/dsn_ext/pcbtestxmldbdata001_test001.xml")
let $style := <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml" /><xsl:template match="/"><xsl:copy-of select="." /></xsl:template></xsl:stylesheet>
return xslt:transform-text($xml,$style)
</text>
</query>
I do the query on BaseX GUI and it works!!!
enter image description here
BUT! When I do the same query on postman to query BaseX on remote server by api ,it fails!
The error messages are:
Stopped at /srv/basex/webapp, 3/19:
[XPST0003] Expecting variable declaration.
enter image description here
I don't know why this error occured.Is there anybody could help me to solve this problem ?
Help!!!!!!!
My baseX versions on local and remote are both 9.5.0
I try it on BaseXGUI and it works correctly
but when I try it on postman then it fails!
I hope the query will work correctly on postman !
The image you show of the BaseX GUI actually shows the query
let $xml := doc("/dsn_ext/pcbtestxmldbdata001_test001.xml")
let $style := <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml" /><xsl:template match="/"><xsl:copy-of select="." /></xsl:template></xsl:stylesheet>
return xslt:transform-text($xml,$style)
(no wrapping <query><text>), which is a valid query.
I don't know Postman but I would expect that it wants the query to be the string value of the <text> element. To achieve that you will need to escape the contained elements, typically by wrapping them in a CDATA section:
<query><text><![CDATA[
let $xml := doc("/dsn_ext/pcbtestxmldbdata001_test001.xml")
let $style := <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml" /><xsl:template match="/"><xsl:copy-of select="." /></xsl:template></xsl:stylesheet>
return xslt:transform-text($xml,$style)
]]></text>
</query>
Related
I need to call the vbscript externally inside the xsl. I have written a sample xml and xsl when I validate the xml against xsl in have an error of cannot create ActiveX Component.
Next I have transformed the xml against the xsl using Altova but I found XML transformation failed due to following error: Function not in namespaceerror in xpath expression,Function not in namespace.
I have inculded the xml below
XML:
<LOOP_ID>
<ID LINE="1" ID00="ISA" ISA01="00" ID02="" ID03="12" ID04="" ID05="11" ID06="111111" ID07="ZZ" ID08="11111" ID09="121005" ID10="1759" ID11="^" ID12="00501" ID13="005926056" ID14="0" ID15="P" ID16=""/>
</LOOP_ID>
xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user="http://mycompany.com/mynamespace">
<msxsl:script language="VBScript" implements-prefix="user">
Function ValidDateFormat(sDateValue)
Dim Test As DateTime
If DateTime.TryParseExact(datetime, sFormat, New CultureInfo("en-US"), DateTimeStyles.None, Test) = True Then
Return "t"
Else
Return "f"
End If
End Function
Function checkDateLessthanCurrID(sValue)
Dim Test As DateTime
If DateTime.TryParseExact(sDate, "yyMMdd", New CultureInfo("en-US"), DateTimeStyles.None, Test) AndAlso Test < DateTime.Now Then
Return "t"
Else
Return "f"
End If
End Function
Function checkDateLessthanCurr(sValue)
Dim Test As DateTime
If DateTime.TryParseExact(datetime, "MM:dd:yyyy", New CultureInfo("en-US"), DateTimeStyles.None, Test) AndAlso Test < DateTime.Now Then
Return "t"
Else
Return "f"
End If
End Function
</msxsl:script>
<xsl:output method="text" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:apply-templates select="/LOOP_ID"/>
</xsl:template>
<xsl:template match="/LOOP_ID">
<xsl:if test="ID/#ID09 !=''">
<xsl:if test="user:checkDateLessthanCurrISA(string(ID/#ID09))='t'">
</xsl:if>
</xsl:if>
I need to validate the date in the attribute given in xml. But I cannot validate showing error cannot find the namespace.
I have also created a external dll for the project and registered using regasm But I cannot access the dll inside my xsl.
Can any one help me to solve the issue?
Your first error:
cannot create ActiveX Component
means that your code was actually executed, but failed, due to a missing ActiveX reference.
You didn't state it, but most likely you received this by using MSXML, because that is the only XSLT compiler I know of that uses ActiveX. It is also used in Internet Explorer.
Your second error:
Next I have transformed the xml against the xsl using Altova but I found XML transformation failed due to following error: Function not in namespaceerror in xpath expression,Function not in namespace.
is strange. If I run it with Altova (I use the 2013 Community version) using the /xslt commandline switch to turn off XSLT 2.0 backwards compatibility processing, it tries to parse the script block and returns the following:
Script Compile Error(s) (relative to script begin):
Line 3, Character 0: 'datetime' is a type and cannot be used as an expression.
Line 3, Character 0: 'sFormat' is not declared. It may be inaccessible due to its protection level.
Line 3, Character 0: Type 'CultureInfo' is not defined.
Line 3, Character 0: 'DateTimeStyles' is not declared. It may be inaccessible due to its protection level.
Line 12, Character 0: 'sDate' is not declared. It may be inaccessible due to its protection level.
Line 12, Character 0: Type 'CultureInfo' is not defined.
Line 12, Character 0: 'DateTimeStyles' is not declared. It may be inaccessible due to its protection level.
Line 21, Character 0: 'datetime' is a type and cannot be used as an expression.
Line 21, Character 0: Type 'CultureInfo' is not defined.
Line 21, Character 0: 'DateTimeStyles' is not declared. It may be inaccessible due to its protection level.
This suggests that the code is not correct. I think the code uses VBScript and the classes you seem to be using are VB.NET.
When running the code against Microsoft's .NET version of XSLT 1.0, I receive the similar errors as above.
It turns out that Microsoft's script parser does not take your code as VBScript (which is ActiveX), but as a VB.NET script. Which is OK, as your code looks like VB.NET.
However, it is literally full of errors. I am not going to fix every error here, but here's a shortened version of your code that runs correctly on both Altova and Microsoft XSLT versions.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">
<xsl:strip-space elements="*"/>
<msxsl:script language="VBScript" implements-prefix="user">
Function ValidDateFormat(sDateValue As String) As String
Dim Test As DateTime
Dim sFormat As String = "MM-dd-YY"
If DateTime.TryParseExact(sDateValue, sFormat, New Globalization.CultureInfo("en-US"), Globalization.DateTimeStyles.None, Test) = True Then
Return "true"
Else
Return "false"
End If
End Function
</msxsl:script>
<xsl:output method="text" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="ID[#ID09 !='']">
<xsl:value-of select="user:ValidDateFormat(string(#ID09))"/>
</xsl:template>
</xsl:stylesheet>
The above returns true or false. I suggest you first try the code inside Visual Studio before you try it with XSLT, because inside XSLT it is quite hard to debug.
On mxsxl:script
In my previous post I was incorrect to assume that msxsl:script was not supported by Altova. Martin Honnen corrected me in the comments. It is supported and it looks like it uses the same code provider underneath as Microsoft uses.
Your original error was an ActiveX error. If you want to run your code with an ActiveX XSLT processor, you will need to do a few more things to get it running. First of all your code is not ActiveX VBScript. Second, you will need to make sure the appropriate ActiveX objects your code required can be instantiated (i.e., are on the system path).
In browsers other than Microsoft Internet Explorer and in other processors, msxsl:script is not supported. .NET scripting is not supported in any browser, use ActiveX scripting instead.
On XSLT 2.0
If you can use Altova, you are essentially using XSLT 2.0, which does not require the extensions you wrote: it can natively compare times and dates, and can get the current date and time. XSLT 2.0 processors include, but are not limited to: Altova (native), Saxon (Java and IKVM.NET), Exselt (.NET), XMLPrime (.NET).
With the program BaseX I was able to use XPath and XQuery in order to query an XML document located at my home directory, but I have a problem with doing the same in XSLT.
The document I'm querying is BookstoreQ.xml.
XPath version, running totally fine:
doc("/home/ioannis/Desktop/BookstoreQ.xml")/Bookstore/Book/Title
XSLT code which I want to execute:
<xsl:stylesheet version = "2.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method= "xml" indent = "yes" omit-xml-declaration = "yes" />
<xsl:template match = "Book"></xsl:template>
</xsl:stylesheet>
I read BaseX' documentation on XSLT, but didn't manage to find a solution. How can I run given XSLT?
BaseX has no direct support for XSLT, you have to call it using XQuery functions (which is easy, though). There are two functions for doing this, one for returning XML nodes (xslt:transform(...)), one for returning text as a string (xslt:transform-text(...)). You need the second one.
xslt:transform-text(doc("/home/ioannis/Desktop/BookstoreQ.xml"),
<xsl:stylesheet version = "2.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method= "xml" indent = "yes" omit-xml-declaration = "yes" />
<xsl:template match = "Book"></xsl:template>
</xsl:stylesheet>
)
Both can either be called with the XSLT as nodes (used here), by passing it as a string or giving a path to a file containing the XSLT code.
I am using the below shown snippet of choice element in my Mule 3.3 flow. XSL Transformer feeds the choice element. XSL Transformer is supposed to return a String (name of an entity) and on the basis of string value, I use choice router to push it to different jms queues.
<flow name="ProcessOrder">
.
.
<xm:xslt-transformer xsl-file="xsl/getEntity.xslt" returnClass="java.lang.String"/>
<choice>
<when expression="payload.contains('ABC')">
<jms:outbound-endpoint queue="order.queue1" />
</when>
<when>
</when>
<otherwise>
</otherwise>
</choice>
</flow>
XSL Transformer returns this payload
<?xml version="1.0" encoding="UTF-8"?>ABC
My question is how do I compare the String returned. I don't think payload.contains() is the best way to do this, though it solves my purpose and also we won't have matching entities returned which are ever like ABCxy but still this is not a full proof solution.
Add the omit-xml-declaration part in your xslt as shown below. This will give you the raw string without the prolog.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/">
...
...
This will give
"ABC" as output instead of "<?xml version="1.0" encoding="UTF-8"?>ABC"
Then in the expression use it like
<when expression="#[message.payload.contains('ABC')]">
This way it should work.
Maybe this is what you are looking for:
<when evaluator="xpath" expression="/result/" ...
Obviously, your XSLT will need to retur a well-formed XML document with the desired result in an XML element that is neatly accessible by XPath.
On Mule website they suggest to use expression-splitter-router evaluator this is an example from mule website of how to use it:
FruitBowl containing an apple, an orange, and two bananas. When Mule receives this object, we want to route the fruit to different locations: the AppleService, BananaService, and OrangeService.
<service name="Distributor">
<inbound>
<jms:inbound-endpoint queue="distributor.queue"/>
</inbound>
<outbound>
<!-- FruitBowl.getFruit() List -->
<expression-splitter-router evaluator="bean" expression="fruit">
<vm:outbound-endpoint path="apple.service.queue">
<payload-type-filter expectedType="org.mule.tck.testmodels.fruit.Apple"/>
</vm:outbound-endpoint>
<vm:outbound-endpoint path="banana.service.queue">
<payload-type-filter expectedType="org.mule.tck.testmodels.fruit.Banana"/>
</vm:outbound-endpoint>
<vm:outbound-endpoint path="orange.service.queue">
<payload-type-filter expectedType="org.mule.tck.testmodels.fruit.Orange"/>
</vm:outbound-endpoint>
</expression-splitter-router>
</outbound>
</service>
Hope that helps
I am trying to pass parameters during an XSLT transformation. Here is the xsl stylesheet.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="param1" select="'defaultval1'" />
<xsl:param name="param2" select="'defaultval2'" />
<xsl:template match="/">
<xslttest>
<tagg param1="{$param1}"><xsl:value-of select="$param2" /></tagg>
</xslttest>
</xsl:template>
</xsl:stylesheet>
The following in the java code.
File xsltFile = new File("template.xsl");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document stylesheet = builder.parse("template.xsl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer xsltTransformer = transformerFactory.newTransformer(new DOMSource(stylesheet));
//Transformer xsltTransformer = transformerFactory.newTransformer(new StreamSource(xsltFile));
xsltTransformer.setParameter("param1", "value1");
xsltTransformer.setParameter("param2", "value2");
StreamResult result = new StreamResult(System.out);
xsltTransformer.transform(new DOMSource(builder.newDocument()), result);
I get following errors:-
ERROR: 'Variable or parameter 'param1' is undefined.'
FATAL ERROR: 'Could not compile stylesheet'
However, if i use the following line to create the transformer everything works fine.
Transformer xsltTransformer = transformerFactory.newTransformer(new StreamSource(xsltFile));
Q1. I just wanted to know whats wrong in using a DOMSource in creating a Transformer.
Q2. Is this one of the ideal ways to substitute values for placeholders in an xml document? If my placeholders were in a source xml document is there any (straightforward) way to substitute them using style sheets (and passing parameters)?
Q1: This is a namespace awareness problem. You need to make the DocumentBuilderFactory namespace aware:
factory.setNamespaceAware(true);
Q2: There are several ways to get the values from an external xml file. One way to do this is with the document function and a top level variable in the document:
<!-- Loads a map relative to the template. -->
<xsl:variable name="map" select="document('map.xml')"/>
Then you can select the values out of the map. For instance, if map.xml was defined as:
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping key="value1">value2</mapping>
</mappings>
You could remove the second parameter from your template, then look up the value using this line:
<tagg param1="{$param1}"><xsl:value-of select="$map/mappings/mapping[#key=$param1]"/></tagg>
Be aware that using relative document URIs will require that the stylesheet has a system id specified, so you will need to update the way you create your DOMSource:
DOMSource source = new DOMSource();
source.setNode(stylesheet);
source.setSystemId(xsltFile.toURL().toString());
In general, I suggest looking at all of the options that are available in Java's XML APIs. Assume that all of the features available are set wrong for what you are trying to do. I also suggest reading the XML Information Set. That specification will give you all of the definitions that the API authors are using.
I am working on the XSLT TBB (using the XSLT Mediator on Tridion 2011 SP1) to retrieve the key Value from the Keyword.
My Keyword looks like this.
Value: Some Value
Key: Its ID is 123
It's a normal Keyword.
I have created a schema with a field. The values will be selected from List and from Category.
The component Source looks like this:
This is the Component source directly taken from the component of Tridion UI.
<Content xmlns="Some Name space">
<keywordlink xlink:href="tcm:202-9737-1024" xlink:title="Some Value"
xmlns:xlink="http://www.w3.org/1999/xlink">Some Value</keywordlink>
</Content>
When I observed the tcm:Component source from template builder, I observed that there are no attributes present for the field.
<Content xmlns="Some Name space">
<keywordlink>Some Value</keywordlink>
</Content>
I want to retrieve the Key value of the keyword.
I wrote a XSLT TBB like this. I am using XSLT mediator to execute XSLT TBBs.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:simple="Some Name space"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:tcm="http://www.tridion.com/ContentManager/5.0"
xmlns:xh="http://www.w3.org/1999/xhtml"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:transform-ext="urn:tridion:transform-ext"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="#default simple xh">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:apply-templates
select="tcm:Component/tcm:Data/tcm:Content/simple:Content" />
</xsl:template>
<xsl:template match="simple:Content">
<xsl:value-of select="simple:keywordlink/#*"/>
<xsl:value-of select=document(simple:keywordlink/#xlink:href)/>
</xsl:template>
<xsl:stylesheet>
I am getting blank output. I want to get the key value of a keyword.
I am getting blank output because in tcm:Component XML, there are no attributes.
I am not sure how can I navigate to that keyword.
I should retrieve the value of Key i.e. "Its ID is 123".
Can any one help how to do this?
It seems it's impossible to get an xlink:href to the referred keyword in a Keyword field using just the XSLT Mediator.
To overcome this I created a .NET compound that "inflates" the extra keyword info in the XML. You'll have to place this compound just before the XSLT compound.
Code:
namespace ContentManagement.TBB.Templates
{
[TcmTemplateTitle("Inflate Keyword Info")]
public class GetExtendedComponent : TemplateBase
{
public override void Transform(Engine engine, Package package)
{
Initialize(engine, package);
Component component = GetComponent();
XmlElement componentXml = component.ToXml();
XmlNamespaceManager ns = new XmlNamespaceManager(componentXml.OwnerDocument.NameTable);
ns.AddNamespace("ns", component.Schema.NamespaceUri);
ItemFields fields = new ItemFields(component.Content, component.Schema);
InflateKeywords(fields, (XmlElement)componentXml.SelectSingleNode(String.Format("//ns:{0}", component.Schema.RootElementName), ns));
ItemFields metaFields = new ItemFields(component.Metadata, component.MetadataSchema);
InflateKeywords(metaFields, (XmlElement)componentXml.SelectSingleNode("//ns:Metadata", ns));
Item xmlItem = package.CreateStringItem(ContentType.Component, componentXml.OuterXml);
package.Remove(package.GetByName(Package.ComponentName));
package.PushItem(Package.ComponentName, xmlItem);
}
private void InflateKeywords(ItemFields fields, XmlElement element)
{
XmlNamespaceManager ns = new XmlNamespaceManager(element.OwnerDocument.NameTable);
ns.AddNamespace("ns", element.NamespaceURI);
Logger.Debug("NS: " + element.NamespaceURI);
foreach (ItemField field in fields)
{
if (field is KeywordField)
{
KeywordField keywordField = (KeywordField)field;
XmlNodeList nodes = element.SelectNodes(String.Format("./ns:{0}", keywordField.Name), ns);
foreach (XmlNode node in nodes)
{
XmlElement kwelement = (XmlElement)node;
Logger.Debug(String.Format("Keyword titel: {0}", keywordField.Value.Title));
Logger.Debug(String.Format("Keyword Element Value: {0}", kwelement.InnerText));
kwelement.SetAttribute("href", "http://www.w3.org/1999/xlink", keywordField.Values.First(v => v.Title.Equals(kwelement.InnerText)).Id);
kwelement.SetAttribute("type", "http://www.w3.org/1999/xlink", "simple");
kwelement.SetAttribute("title", "http://www.w3.org/1999/xlink", kwelement.InnerText);
}
}
else if (field is EmbeddedSchemaField)
{
EmbeddedSchemaField embedField = (EmbeddedSchemaField)field;
XmlNodeList nodes = element.SelectNodes(String.Format("./ns:{0}", embedField.Name), ns);
int i = 0;
foreach (XmlNode node in nodes)
{
XmlElement embedElement = (XmlElement)node;
InflateKeywords(embedField.Values[i], embedElement);
i++;
}
}
}
}
}
}
The Key of the Keyword is not stored in the link (which really only contains the minimal information needed to look up the Keyword). So you'll have to load the Keyword and read it from there.
Yoav showed how to read other items from within your XSLT here:
http://yoavniran.wordpress.com/2009/07/11/implementing-the-xslt-mediator-part-1/
This snippet seems relevant:
<xsl:attribute name="alt">
<xsl:value-of select="document(simple:image/#xlink:href)/tcm:Component/tcm:Data/tcm:Metadata/image:Metadata/image:altText"/>
</xsl:attribute>
So the document() call loads the linked item (in this case a multimedia component) and the rest of the select then finds the value they are looking for.
A keyword XML looks like this:
<?xml version="1.0"?>
<tcm:Keyword xmlns:transform-ext="urn:tridion:transform-ext"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:tcm="http://www.tridion.com/ContentManager/5.0"
IsEditable="false" ID="tcm:1-233-1024">
<tcm:Context>
<tcm:Publication xlink:title="000 Parent Publication" xlink:href="tcm:0-1-1"
xlink:type="simple"/>
<tcm:OrganizationalItem xlink:title="Places" xlink:href="tcm:1-37-512"
xlink:type="simple"/>
</tcm:Context>
<tcm:Info>
<tcm:LocationInfo>
<tcm:WebDAVURL>/webdav/000%20Parent%20Publication/Places/New%20Keyword.tkw</tcm:WebDAVURL>
<tcm:Path>\000 Parent Publication\Places</tcm:Path>
</tcm:LocationInfo>
<tcm:BluePrintInfo>
<tcm:OwningPublication xlink:title="000 Parent Publication" xlink:href="tcm:0-1-1" xlink:type="simple"/>
<tcm:IsShared>false</tcm:IsShared>
<tcm:IsLocalized>false</tcm:IsLocalized>
</tcm:BluePrintInfo>
<tcm:VersionInfo>
<tcm:CreationDate>2012-06-11T09:09:03</tcm:CreationDate>
<tcm:RevisionDate>2012-06-11T09:09:03</tcm:RevisionDate>
<tcm:Creator xlink:title="TCMHOSTNAME\Administrator"
xlink:href="tcm:0-11-65552" xlink:type="simple"/>
</tcm:VersionInfo>
<tcm:AllowedActions>
<tcm:Actions Managed="0" Deny="96" Allow="268560384"/>
</tcm:AllowedActions>
</tcm:Info>
<tcm:Data>
<tcm:Title>New Keyword</tcm:Title>
<tcm:Description>New Keyword</tcm:Description>
<tcm:Key>Key</tcm:Key>
<tcm:IsAbstract>false</tcm:IsAbstract>
<tcm:ParentKeywords/>
<tcm:RelatedKeywords/>
<tcm:MetadataSchema xlink:title="" xlink:href="tcm:0-0-0" xlink:type="simple"/>
<tcm:Metadata/>
<tcm:IsRoot>true</tcm:IsRoot>
</tcm:Data>
</tcm:Keyword>
Implement this way:-
To get the Value field:-
document(simple:keywordlink/#xlink:href)/tcm:Keyword/tcm:Data/tcm:Title/text()
<xsl:value-of select="document(simple:keywordlink/#xlink:href)/tcm:Keyword/tcm:Data/tcm:Title/text()" />
Result:
Some Value
To get the Key field:-
document(simple:keywordlink/#xlink:href)/tcm:Keyword/tcm:Data/tcm:Key/text()
<xsl:value-of select="document(simple:keywordlink/#xlink:href)/tcm:Keyword/tcm:Data/tcm:Key/text()" />
Result:
Its ID is 123