Domanda

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/ :*

  1. As @michael.hor257k pointed out, there are two templates that matches the <book> element.
  2. 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]
  3. 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.
È stato utile?

Soluzione

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.

Altri suggerimenti

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"/>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top