Rod
Rod

Reputation: 15475

not sure why all text is being printed when specific template exists

I have a template element that is specific to listitems nodes.

xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:output method="text"/>

  <xsl:template match="listitems">
    <xsl:value-of select="@status" />
  </xsl:template>

</xsl:stylesheet>

xml

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="callvsapply.xslt"?>
<!-- sample XML snippet -->
<xml>
  <foo status="No">You are here.</foo>
  <bar status="Yes">Hello Bar!</bar>
  <baz status="No">Hello Baz!</baz>
  <listitems status="Yes" id="13" />
  <listitems status="No" id="12" />
</xml>

results

  You are here.
  Hello Bar!
  Hello Baz!
  Yes
  No

Why does all text print? I expected just Yes and No.

Upvotes: 0

Views: 56

Answers (2)

JLRishe
JLRishe

Reputation: 101728

XSLT has a concept of "built-in template rules", which are templates that are used if no relevant template is defined for the current node to which templates are being applied.

They look like this:

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

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

<xsl:template match="processing-instruction()|comment()"/>

What these boil down to is:

  • If the current node is an element or the root node, apply templates to all child nodes.
  • If the current node is a text node or attribute node, place its value in the output.
  • If the current node is a processing instruction or comment, do nothing.

So basically, XSLT's default behavior, if no templates are specified at all, is to walk the document from top to bottom, outputting the value of all text nodes along the way. That is what you are seeing - your XSLT is outputting all text it encounters on the way down.

To remedy this in your case, there are two basic approaches:

First approach: intercept the processing at the root node (or at the document element), and directly target the nodes you want to process from there:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:output method="text"/>

  <xsl:template match="/*">
    <xsl:apply-templates select="listitems" />
  </xsl:template>

  <xsl:template match="listitems">
    <xsl:value-of select="@status" />
  </xsl:template>

</xsl:stylesheet>

Second approach: override the built-in processing for text nodes, so that their values are not sent to the output by default:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:output method="text"/>

  <xsl:template match="listitems">
    <xsl:value-of select="@status" />
  </xsl:template>

  <xsl:template match="text()" />

</xsl:stylesheet>

Upvotes: 3

Rupesh_Kr
Rupesh_Kr

Reputation: 3435

You have to first delete all elements that you don't need to print.

For this you can use this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">

        <xsl:output method="text"/>

        <xsl:template match="listitems">
                <xsl:value-of select="@status" />
        </xsl:template>

        <xsl:template match="node()|@*">
                <xsl:apply-templates/>
        </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions