Reputation: 11112
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/ :*
<book>
element.<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.Upvotes: 3
Views: 1398
Reputation: 163262
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.
Upvotes: 3
Reputation: 122364
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"/>
Upvotes: 1
Reputation: 116959
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)..
Upvotes: 2
Reputation: 86744
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.
Upvotes: 3