Search code examples
xsltxpathvalue-of

XSLT value-of with multiple children of different types


why do I get with that data:

<A>
  <B>block 1</B>
  <B>block 2</B>
  <C>
    no
  </C>
  <B>block 3</B>
</A>

and this transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method= "html" indent="yes"/>

<xsl:template match="A/B">
  <xsl:value-of select="."/> <br/>
</xsl:template>

</xsl:stylesheet>

the following output:

block 1
block 2
no block 3

I'd expect it to be:

block 1
block 2
block 3

So: Why does the C block getting included?

//EDIT Tested with the thing here: http://www.ladimolnar.com/JavaScriptTools/XSLTransform.aspx


Solution

  • Because of the Default Template Rules.

    <xsl:template match="*|/">
      <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="text()|@*">
      <xsl:value-of select="."/>
    </xsl:template>
    

    The XSL processor examines each node in turn, looking for a matching template. If it doesn't find one, it uses the default template, which just outputs the text. In your case the following happens ("no match" means no match in your stylesheet):

    /A         no match, apply-templates (default element template)
    /A/B       match, output text
    /A/B       match, output text
    /A/C       no match, apply-templates
    /A/C/text  no match, output text (default text template)
    /A/B       match, output text
    

    To skip the path /A/C just add an empty template

    <xsl:template match="A/C"/>
    

    This will match the unwanted element and suppress output.