For parsing some strings, I want to use analyze-string(), if available, and provide a slower fallback that works with XSLT 2.0. This is a quick test I did:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template name="tokenize"
use-when="not(function-available('analyze-string'))">
2.0
</xsl:template>
<xsl:template name="tokenize" version="3.0"
use-when="function-available('analyze-string')">
3.0
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="tokenize"/>
<xsl:value-of select="function-available('analyze-string')"/>
</xsl:template>
</xsl:stylesheet>
I ran this inside oXygen 15.2 with Saxon-PE/EE 9.5.1.3. Strangely, the output is
2.0
true
which indicates that the first template was included rather than the second, although its use-when attribute should have evaluated to true, as the second line of the output indicates. What went wrong?
Are there standard best practices when developing a stylesheet targeted at both 2.0 and 3.0 processors? Saxon HE accepts the stylesheet if I use the option -xsltversion:2.0 to override the version attribute on the xsl:stylesheet element. I also tried to set the version attribute to 2.0 to make overriding superfluous, but then function-available('analyze-string') will evaluate to false in Saxon PE/EE, even if I prefix it with the XPath functions namespace.
In Saxon 9.5, for reasons which now escape me, the static context for use-when expressions includes only the core XPath 2.0 functions plus a few selected XSLT functions such as element-available, system-property, and function-available; it doesn't include XPath 3.0 functions such as analyze-string, even though these are available in "ordinary" XPath expressions within the stylesheet. I suspect this reflects the state of the XSLT 3.0 specification at the time Saxon 9.5 was released in 2013. The situation will have changed in 9.6 and 9.7.
Related
I have a stylesheet with a document() function. It finds the external document when i run it with saxon's transform on .Net, but not when i run it using java -jar saxon...
Please tell me that is well documented behavior and where it is documented!
Thank you guys!
EDIT:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<root>
<xsl:variable name="dict" select="document('file:../data/mpxvoc.xml')"/>
<xsl:message>
<xsl:value-of select="doc-available('file:../data/mpxvoc.xml')"/>
<xsl:value-of select="$dict/*/*[1]"/>
</xsl:message>
</root>
</xsl:template>
</xsl:stylesheet>
EDIT2: Yes, same version!
EDIT3: Beginning of -t output on .NET/transform
C:\Users\mauri\OneDrive\smbdata\EM\SM-Plains\20200806>transform -t -s:2-MPX\vfix.mpx -xsl:C:\Users\mauri\eclipse-workspace\Pipeline\xsl\dtest.xsl -o:o.xml
Saxon-HE 9.9.1.6N from Saxonica
.NET 4.0.30319.42000 on Microsoft Windows NT 6.2.9200.0
URIResolver.resolve href="file:/C:/Users/mauri/eclipse-workspace/Pipeline/xsl/dtest.xsl" base="null"
Stylesheet compilation time: 1.25987s (1259.87ms)
Processing file:/C:/Users/mauri/OneDrive/smbdata/EM/SM-Plains/20200806/2-MPX/vfix.mpx
Using parser org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser
Building tree for file:///C:/Users/mauri/OneDrive/smbdata/EM/SM-Plains/20200806/2-MPX/vfix.mpx using class net.sf.saxon.tree.tiny.TinyBuilder
Tree built in 222.8786ms
Tree size: 42580 nodes, 902487 characters, 26182 attributes
Building tree for file:///C:/Users/mauri/eclipse-workspace/Pipeline/data/mpxvoc.xml using class net.sf.saxon.tree.tiny.TinyBuilder
Tree built in 59.3813ms
Tree size: 20788 nodes, 725994 characters, 10214 attributes
...
Java version:
C:\Users\mauri\OneDrive\smbdata\EM\SM-Plains\20200806>java -jar "C:\Program Files\Saxonica\SaxonHE10-2J\saxon-he-10.2.jar" -t -s:2-MPX\vfix.mpx -xsl:C:\Users\mauri\eclipse-workspace\Pipeline\xsl\dtest.xsl -o:o.xml
Saxon-HE 10.2J from Saxonica
Java version 1.8.0_261
Stylesheet compilation time: 635.9066ms
Processing file:/C:/Users/mauri/OneDrive/smbdata/EM/SM-Plains/20200806/2-MPX/vfix.mpx
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Building tree for file:/C:/Users/mauri/OneDrive/smbdata/EM/SM-Plains/20200806/2-MPX/vfix.mpx using class net.sf.saxon.tree.tiny.TinyBuilder
Tree built in 348.0487ms
Tree size: 42580 nodes, 902487 characters, 26182 attributes
URIResolver.resolve href="file:../data/mpxvoc.xml" base="file:/C:/Users/mauri/eclipse-workspace/Pipeline/xsl/dtest.xsl"
falseError FODC0002 while evaluating xsl:message at line 12 of file:/C:/Users/mauri/eclipse-workspace/Pipeline/xsl/dtest.xsl: Document has been marked not available: file:../data/mpxvoc.xml
Execution time: 414.5074ms
Memory used: 62Mb
URIResolver shows different bases. Is that it and is there a quick fix to get the same result in java?
The URI file:../data/mpxvoc.xml is not a valid URI acccording to RFC 8089. Saxon however takes a liberal approach to URIs, in this context it passes the URI to the XML parser "as is", and if the parser is prepared to accept it then that's fine. At this point differences between platforms may well appear.
The solution is to avoid using URIs that don't conform to the standards. If you want a relative URI resolved against the base URI of the stylesheet, then drop the "file:" part.
RFC 8089 was only published in 2017, and until then the specs for the file URI scheme were hopelessly vague. The 2017 spec was far too late to make a real difference, since by then existing platforms like Java and .NET had to maintain compatibility with their respective past decisions. But if you stick to RFC 8089, you should be able to achieve reasonable portability.
I am planning to used XSL version 3.0 for my WSO2 EI application. Because, I need to map JSON to JSON and JSON to XML in my application. Currently I have try with version 2.0. Please refer following code for current implementation.
I need to know how change this version and which jar required in WSO2EI for xsl version 3.0.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:param name="STATIC_BODY_PARAM"></xsl:param>
<xsl:template match="/availabilityRequest">
<availabilityRequest>
<control>
<userName>
<xsl:value-of select="control/userName" />
</userName>
<passWord>
<xsl:value-of select="control/passWord" />
</passWord>
</control>
....................
</availabilityRequest>
</xsl:template>
</xsl:stylesheet>
When I used version as 3.0, I got following error message. I have added your further reference.
ERROR - XSLTMediator Error creating XSLT transformer using : Value {name ='null', expression =fn:concat('gov:repository/transformation/',$ctx:uri.var.travel_type,'_',$ctx:uri.var.activity,'_',$ctx:uri.var.supplier_id,'_in.xslt')}
net.sf.saxon.trans.LicenseException: Requested feature (XSLT 3.0) requires Saxon-PE
at net.sf.saxon.Configuration.checkLicensedFeature(Configuration.java:584)
at net.sf.saxon.PreparedStylesheet.setStylesheetDocument(PreparedStylesheet.java:331)
at net.sf.saxon.PreparedStylesheet.prepare(PreparedStylesheet.java:207)
at net.sf.saxon.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:132)
at org.apache.synapse.mediators.transform.XSLTMediator.createTemplate(XSLTMediator.java:467)
I don't know anything specifically about WSO2EI, but it appears (from your link) that it is currently running with some older version of Saxon-HE.
Simply substituting the Saxon 9.9 JAR file for the one that is distributed with the product may work, or it may not. It's very likely to work, but it's possible that the stylesheets, or the calling application, depend on something in Saxon that has changed.
If you've tried something, there's no point telling us it doesn't work. You need to tell us exactly how it failed.
You should try running a stylesheet that outputs the value of system-property('xsl:product-version') so you have positive confirmation of which Saxon version is being picked up.
You don't need to make any changes to your stylesheets to use XSLT 3.0 features, but it's a good idea to change the version attribute to version="3.0" for documentation reasons.
I have fixed above problem using following information.
I got the 30 trail license key with registering http://www.saxonica.com/download/download.xml (saxon-license.lic) and it put into /wso2ei-6.4.0/ folder
Remove this jar (saxon.he_9.4.0.wso2v1.jar) on following location. (/wso2ei-6.4.0/wso2/components/plugins)
Also put this jar (saxon9ee.jar) http://www.saxonica.com/download/SaxonEE9-4-0-6J.zip into /wso2ei-6.4.0/lib location
Restart the wso2ei-6.4.0 server
Now xsl:stylesheet version="3.0" working without any issue.
I have got those details from following link. Many thanks for that.
http://nandikajayawardana.blogspot.com/2012/12/how-to-replace-saxonhe940wso2v1jar-in.html
As I know there's no out of box XSLT function for advanced calculation, anyone have any idea how I can do math such as Cosine/Sin() within XSLT? The requirement is also very specific which I need the extension to be downloadable(instead of pointing to a url) so that I can download it and reference as source within my XSL script. I am unable to download EXSLT source files to try as it seems like there's an issue with that page. Can you please also provide a simple example of how to reference the source within the script and calculate something simple like:
<input>
<num1>1</num1>
<num2>1</num2>
</input>
and have the output as:
<output>
<cosOfnum1>0.54030230586</cosOfnum1>
<sinOfnum2>0.8414709848</sinOfnum2>
</output>
Thank you!
Saxon 9 (including HE, tested with 9.6, see also http://saxonica.com/html/documentation9.6/functions/math/sin.html saying "From Saxon 9.6, available in all editions.") does have out of the box support for the functions defined in https://www.w3.org/2005/xpath-functions/math/, here is an example:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="2.0">
<xsl:template match="input">
<output>
<xsl:apply-templates/>
</output>
</xsl:template>
<xsl:template match="num1">
<cosOfnum1>
<xsl:value-of select="math:cos(.)"/>
</cosOfnum1>
</xsl:template>
<xsl:template match="num2">
<sinOfnum2>
<xsl:value-of select="math:sin(.)"/>
</sinOfnum2>
</xsl:template>
</xsl:stylesheet>
I have also tested that XmlPrime 4 runs the above stylesheet correctly when using the command line option --xt30 so it also has built-in support for those functions.
Altova XMLSpy 2017 also supports the functions in the namespace xmlns:math="http://www.w3.org/2005/xpath-functions/math" out of the box but only in version="3.0" stylesheets.
As I know there's no out of box XSLT function for advanced
calculation, anyone have any idea how I can do math such as
Cosine/Sin() within XSLT?
Using the FXSL library, one can have among other things trigonometric functions, written in pure XSLT 1.0 or XSLT 2.0:
http://fxsl.sourceforge.net/articles/xslCalculator/The%20FXSL%20Calculator.html#The_Trigonometric_Functions
The Math modules of FXSL implement:
The wellknown trigonometric functions: sin(), cos(), tan(), cot(), sec(), csc()
Hyperbolic trigonometric functions: hsin(), hcos(), htan(), hcot(), hsec(), hcsc()
Exponential and logarithmic functions: exp(), ln(), log10(), log2(), log(), pow(), sqrt()
Solving equations of one real variable: the Newton - Raphson's method and the Binary Search method.
Inverse functions: arcsin(), arccos(), arctan(), arccot(), arcsec(), arccsc(), archsin(), archcos(), archtan(), archcot(), archsec(), archcsc(),
I have been trying my XSLT code in the online tool [XSLT 1.0 processor]:
http://www.freeformatter.com/xsl-transformer.html
Recently, I had to make use of xs:dateTime and hence started using the tool that uses XSLT 2.0 processor,
http://xsltransform.net/
Now, when i was trying to solve a problem, i see that i get different output for the same input XML in these two processors. The code posted here is not the real code i am working on; this is to simulate the weird output i faced.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<book>
<title></title>
</book>
<phone>apple</phone>
</items>
XSLT:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
indent="yes" />
<xsl:template match="/">
<items><xsl:apply-templates select="items/*" /></items>
</xsl:template>
<!-- ignore empty elements -->
<xsl:template match="*[not(normalize-space())]" />
<xsl:template match="book">
<newbook><xsl:apply-templates /></newbook>
</xsl:template>
<xsl:template match="title">
<newtitle><xsl:apply-templates /></newtitle>
</xsl:template>
<xsl:template match="phone">
<newphone><xsl:apply-templates /></newphone>
</xsl:template>
</xsl:stylesheet>
Output from http://xsltransform.net/ : [output 1]
<?xml version="1.0" encoding="UTF-8"?>
<items>
<newbook>
<newtitle/>
</newbook>
<newphone>apple</newphone>
</items>
Output from http://www.freeformatter.com/xsl-transformer.html : [output 2]
<?xml version="1.0" encoding="UTF-8"?>
<items>
<newphone>apple</newphone>
</items>
Expected output XML is output 2 .
Any idea why this different output behavior?
note: I looked at another SO question: Generating two different outputs for the same XSL file?, but that is different.
Edit
To add more clarity on which tool produced which output:
http://xsltransform.net/ produced output 1
http://www.freeformatter.com/xsl-transformer.html produced output 2
Update[02/10/2014] - regarding solution
Since the correct answer was first provided by Jim Garrison, that's marked as answer. However, there are other important points as well, as pointed out by others, Hence I am wrapping up all here.
<xsl:template match="*[not(normalize-space())]" />
The above template eliminates the empty nodes in both XSLT1 and XSLT2. Hence output 2 is correct
*Reason for getting output 1 from the tool - http://xsltransform.net/ :*
As #michael.hor257k pointed out, there are two templates that matches the <book> element.
The tool was using Saxon-HE 9.5.1.3, and the output 1 behavior was probably a bug that was fixed in the latest maintenance release [#Michael Kay explained well in his answer]
As #Ian Roberts mentioned in his answer, there is a concept of default priorities that are assigned to different types of templates.
Changing the template syntax to:
<xsl:template match="*[not(normalize-space())]" priority="2"/>
yields the same output in both the tools regardless of Saxon version, because we are explicitly defining the priority to the template.
Output 2 is correct. I ran your example in Oxygen/XML, using both XSLT1 and XSLT2 and got the correct results for both. Your template
<xsl:template match="*[not(normalize-space())]" />
eliminates the empty nodes in both XSLT1 and XSLT2.
Therefore the only possible conclusion is that the online tool that produced your Output 1 has a bug.
I get the correct result running with Saxon-EE 9.5.1.4; the xsltransform site is running Saxon-HE 9.5.1.3. It's probably a bug that we fixed in the latest maintenance release; I'll do some chasing to see if I can finger it.
Note that an empty <book> element matches two of your templates:
<xsl:template match="*[not(normalize-space())]" />
and:
<xsl:template match="book">
<newbook><xsl:apply-templates /></newbook>
</xsl:template>
The same thing applies to an empty <title> element. Such conflicts must be resolved by the XSLT processor, using the priorities specified in the XSLT specification.
The result you report from http://xsltransform.net/ is generated by Saxon 9.5.1 - an XSLT 2.0 engine. You will get a different result (on the same site) if you switch to an XSLT 1.0 engine (Saxon 6.5 or Xalan 2.7.1).
I don't know if the conflict resolution rules have changed in XSLT 2.0 compared to XSLT 1.0; I am getting a different result myself when using Saxon 8.9 - also an XSLT 2.0 processor. Perhaps we will be fortunate enough to hear from Michael Kay regarding this difference (I have added a Saxon tag to your question to get his attention)..
Output 2 is definitely the correct one according to both the 1.0 and 2.0 XSLT specs for the stylesheet you give in the question. However you say this is simplified when compared to your real stylesheet.
The thing that makes it work is the default priorities that are assigned to different types of templates. These are the same in both XSLT versions, and a match pattern that involves a predicate will overrule one that is just a single element name test.
However a match that involves hierarchy (e.g. match="items/book") or anything more complex than just a single element name will get the same priority as the *[....] rule by default - 0.5. If you've got any of these kinds of patterns in your real XSLT then you need to add an explicit priority higher than 0.5 to the "blank-suppressor" template.
<xsl:template match="*[not(normalize-space())]" priority="2"/>
I have the following in an XLST document
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:str="http://xsltsl.org/string" xmlns:dt="http://xsltsl.org/date-time" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:if test="document('../folder/somefile.xml')">
<!-- do stuff -->
</xsl:if>
In IE8 and IE9 attempting to process this file results in a JavaScript error,"The system cannot locate the object specified" - and the transform bugs out.
I have read about a 'doc-available' function in XLST2.0, but attempting to use it just gives me an error that the function is not available.
I have seen this question: How check document is available in xsl? - but I'd prefer not to add processor dependent code, so I'm hoping I'm just missing something with 'doc-available'.
I think the XSLT 1.0 specification (and MSXML used by IE is an XSLT 1.0 processor) allows the XSLT processor do either "signal an error" or to continue by returning an empty node set if a document() call fails. Thus MSXML reporting an error is allowed and not a bug. You will need to make sure outside of XSLT that the file exists.