I need help with one of my issues. I am new to XSLT. Right now I am trying to write an XSLT which will generate text output (example: "01:30").
In my XSLT 2.0, I am calling the XPath function hours-from-duration($duration) and this function is throwing the error
XPath is invalid
I can also see the above error in the following logs. Please help me with my issues. Thanks...
16:01:39,403 ERROR [main] JAXPSAXProcessorInvoker - Error checking type of the expression 'funcall(hours-from-duration, [variable-ref(duration/node-set)])'.
16:01:39,404 ERROR [main] JAXPSAXProcessorInvoker - Could not compile stylesheet
javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:858) at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:648)
My XSLT:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="http://exslt.org/dates-and-times"
xmlns:str="http://exslt.org/strings"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
version="1.0" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="text" />
<xsl:variable name="request" select="/*[local-name()='Payout']/*[local-name()='Request']" />
<xsl:variable name="duration" select="$request/Time" />
<xsl:template match="/">
<xsl:value-of select="(hours-from-duration($duration))"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="(minutes-from-duration($duration))"/>
</xsl:template>
</xsl:stylesheet>
XML Input:
<Payout>
<Request Commit="true" Transaction="false">
<Month>JAN</Month>
<Time>P01H30M33S</Time>
</Request>
</Payout>
Your duration value is invalid. It is missing a "T". It should be PT01H30M33S.
hours-from-duration() is an XPath 2.0 function. You are using Xalan, which only supports XSLT 1.0 and XPath 1.0.
Furthermore, these functions expect an object of type xs:duration. You are passing it a node (a Time element). If you switch to an XSLT 2.0 processor, you will need either (a) to make sure the processor is schema-aware and Time is validated as an xs:duration, or (b) to convert it to type xs:duration explicitly, by calling xs:duration(Time).
And of course you will need to make sure it's a valid duration as pointed out by #MadsHansen
Related
I noticed when trying to use disable-output escaping in XSLT3 in Saxon that it would not work if expand-text was set to yes on the stylesheet or even on the given match template
The following code (when run on itself) shows the issue (in Saxon 9.8.0.12).
I know this is an unusual combination and that disable-output-escaping in normally to be avoided at all costs but just trying to ascertain correct behavior.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:template match="/">
<out>
<xsl:apply-templates/>
</out>
</xsl:template>
<xsl:template match="xsl:stylesheet" expand-text="true">
<expandtext>
<count>{count(*)}</count>
<xsl:text disable-output-escaping="true"><test/></xsl:text>
</expandtext>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="xsl:template" expand-text="false">
<notexpandtext>
<count>{count(*)}</count>
<xsl:text disable-output-escaping="true"><test/></xsl:text>
</notexpandtext>
</xsl:template>
</xsl:stylesheet>
produces
<?xml version="1.0" encoding="UTF-8"?>
<out>
<expandtext><count>3</count><test/></expandtext>
<notexpandtext><count>{count(*)}</count><test/></notexpandtext>
<notexpandtext><count>{count(*)}</count><test/></notexpandtext>
<notexpandtext><count>{count(*)}</count><test/></notexpandtext>
</out>
Indeed there is a bug here, which I have logged at
https://saxonica.plan.io/issues/4412
An xsl:text instruction within the scope of expand-text="yes" is implemented internally as a different kind of expression from a "plain old" xsl:text element, and the new expression overlooked the need to support d-o-e.
I have added a test case disable-output-escaping/doe-0201 to the XSLT 3.0 test suite at https://github.com/w3c/xslt30-test
I am doing transform xml file using xslt and I want to display the error message of xslt parser in an element
Note: Error message should be original of parser message
I am not sure there is a way to capture XML parsing errors of the primary input document to an apply-templates based XSLT 3 transformation but in general XSLT 3 with xsl:try/xsl:catch allows you to capture and handle run-time errors, so assuming you can organize the rest of your code (for instance by using a named template as the starting point) to load/parse any XML documents with the doc or document function then you can use try/catch to handle parsing errors. An example is https://xsltfiddle.liberty-development.net/ej9EGcg/2
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:err="http://www.w3.org/2005/xqt-errors"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template match="/">
<root>
<xsl:try>
<xsl:variable name="doc1" select="doc('https://raw.githubusercontent.com/martin-honnen/martin-honnen.github.io/master/xslt/2019/test2019032601.xml')"/>
<xsl:value-of select="count($doc1//item)"/>
<xsl:catch>Error code: <xsl:value-of select="$err:code"/>
Reason: <xsl:value-of select="$err:description"/>
</xsl:catch>
</xsl:try>
</root>
</xsl:template>
</xsl:stylesheet>
which, depending on your needs, can also be reduced to directly use the relevant XPath expression with the select attribute of the xsl:try element e.g. https://xsltfiddle.liberty-development.net/ej9EGcg/3
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:err="http://www.w3.org/2005/xqt-errors"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template match="/">
<root>
<xsl:try select="count(doc('https://raw.githubusercontent.com/martin-honnen/martin-honnen.github.io/master/xslt/2019/test2019032601.xml'))">
<xsl:catch>Error code: <xsl:value-of select="$err:code"/>
Reason: <xsl:value-of select="$err:description"/>
</xsl:catch>
</xsl:try>
</root>
</xsl:template>
</xsl:stylesheet>
I could not able to access PartNumber/Description value under attribute tag with below xpath but and soap xml is given below.Let me know any further details required.
Please help on this.Thanks inadvance!.
Xpath being used And SOAP XML Message:
<xsl:value-of select="/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='PullCustomerPartsPricingResponse']/*[local-name()='PullCustomerPartsPricingResult']/*[local-name()='CustomerPart']/#*[local-name()='PartNumber']"/>
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header />
<s:Body>
<PullCustomerPartsPricingResponse xmlns="http://cdx.dealerbuilt.com/Api/0.99/">
<PullCustomerPartsPricingResult xmlns:a="http://schemas.datacontract.org/2004/07/DealerBuilt.BaseApi" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:CustomerPart>
<a:Placement>
<a:GroupId>10</a:GroupId>
</a:Placement>
<a:Attributes xmlns:b="http://schemas.datacontract.org/2004/07/DealerBuilt.Models.Parts">
<b:AddedDate>2017-12-19T00:00:00</b:AddedDate>
<b:DealerPartId>287925</b:DealerPartId>
<b:Description>BAT (51/500AMP85)</b:Description>
<b:PartNumber>31500SB2yy1M</b:PartNumber>
<b:QuantityLostMonthToDate>0</b:QuantityLostMonthToDate>
</a:Attributes>
<a:PartKey>GZ287925</a:PartKey>
<a:CustomerListPrice xmlns:b="http://schemas.datacontract.org/2004/07/DealerBuilt.Models">
<b:Amount>130.49</b:Amount>
<b:Currency>UsDollar</b:Currency>
</a:CustomerListPrice>
</a:CustomerPart>
</PullCustomerPartsPricingResult>
</PullCustomerPartsPricingResponse>
</s:Body>
</s:Envelope>
Regards
Vardhan
You have ended your long xpath expression with this..
/#*[local-name()='PartNumber']
But PartNumber is not an attribute. It is an element named PartNumber that is a child of an element that happened to be named Attributes, but that does not actually make it an attribute in XML terms!
It should look like this...
<xsl:value-of select="/*[local-name()='Envelope']
/*[local-name()='Body']
/*[local-name()='PullCustomerPartsPricingResponse']
/*[local-name()='PullCustomerPartsPricingResult']
/*[local-name()='CustomerPart']
/*[local-name()='Attributes']
/*[local-name()='PartNumber']"/>
Although it would be really better if you declared the namespaces in your XSLT and used then in your xpath.
NameSpaces from the request XML need to be used in xslt as well.Following xsl gave the PartNumber value.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:a="http://schemas.datacontract.org/2004/07/DealerBuilt.BaseApi" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:b="http://schemas.datacontract.org/2004/07/DealerBuilt.Models.Parts">
<xsl:output method="xml" version="1.0"/>
<xsl:template match="/">
<xsl:value-of select="*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='PullCustomerPartsPricingResponse']/*[local-name()='PullCustomerPartsPricingResult']/*[local-name()='CustomerPart']/*[local-name()='Attributes']/*[local-name()='PartNumber']"/>
</xsl:template>
</xsl:stylesheet>
In order to use xpath-functions (specifically the fn part), I included the respective namespace into my xslt stylesheet, like so:
<xsl:stylesheet
version="2.0"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
>
As specified by W3C.
However, when I use fn:document-uri, my XSLT engines tell me I called an unknown function/extension:
<xsl:variable name="uri" select="fn:document-uri()" />
Opera says:
This document had an invalid XSLT stylesheet. Error message from the XSLT engine:
Error: XPath expression compilation failed: fn:document-uri()
Details: compilation error (characters 1-17, "fn:document-uri()"): unknown function called: '{ http://www.w3.org/2005/xpath-functions, document-uri }'
Firefox says:
Error during XSLT transformation: An unknown XPath extension function was called.
And xsltproc refuses transformation, because of xslt 2.0.
So, how do I specify the fn namespace properly?
The problem is that you are using an XSLT 1.0 processor and an XSLT 1.0 processor doesn't know (and must not know) anything about XPath 2.0 functions.
If you use a real XSLT 2.0 processor, you don't even have to specify the function namespace -- it is a default namespace for any unprefixed function name.
For example, this XSLT 2.0 transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select="document-uri(.)" />
<xsl:text>
</xsl:text>
<xsl:sequence select="document-uri(document(''))" />
</xsl:template>
</xsl:stylesheet>
when executed with Saxon 9.1.5 under the XSelerator, produces correctly the URLs of the source XML document and the stylesheet itself:
file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml
file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xsl
I have an XSL which generates a XML file
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="filename" select="concat('TextTypes','.html')" />
<xsl:result-document method="html" href="{$filename}">
<font name="{$truncatedFont}" size="{$truncatedSize}" style="{#styleOverride}" env="{$env}" lang="{#language}" />
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
When I run the XSLT i get the error:
ERROR: 'Unsupported XSL element 'http://www.w3.org/1999/XSL/Transform:result-document''
Error during transformation
javax.xml.transform.TransformerException: java.lang.RuntimeException: Unsupported XSL element 'http://www.w3.org/1999/XSL/Transform:result-document'
I have specified ny XSLT verision as 2.0. I am confused on why i get this error. Please help.
XSLT 2.0 is only supported by a few XSLT processors, I think with Java there is only Saxon 9 and with IBM's websphere you can also use IBM's XSLT 2.0 processor but the XSLT processor in the Oracle respectively SUN JRE and JDK is based an Apache Xalan and only supports XSLT 1.0.
Looks like your xslt processor does not support version 2.0.
It depends on how you're running your XSLT nishMaria.
If you can daisy chain XSLT then you can process the input document multiple times to produce multiple different output files or produce one output file with all the desired output then pass this file through a number of XSLT's each of which just selects part of the output.