why does the previous code output TEXT, why should I insist that XSL ignore all other text? is that the behavior of all XML parsers or just my own
You discover one of the most fundamental XSLT functions as specified in the Specification: XSLT built-in templates .
From the specification :
There is a built-in template rule that allows you to continue recursive processing if there is no successful pattern matching using an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The equivalent of the built-in template rule is shown below:
<xsl:template match="*|/"> <xsl:apply-templates/> </xsl:template>
There is also a built-in template rule for each mode, which allows you to continue recursive processing in the same mode if there is no successful pattern matching using an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The equivalent of the built-in template rule for mode m is shown below.
<xsl:template match="*|/" mode="m"> <xsl:apply-templates mode="m"/> </xsl:template>
There is also a built-in template rule for text nodes and attributes that copies text through:
<xsl:template match="text()|@*"> <xsl:value-of select="."/> </xsl:template>
Built-in template rule for processing instructions and comments - do nothing.
<xsl:template match="processing-instruction()|comment()"/>
The built-in template rule for namespace nodes also does nothing. There is no template that can match the namespace node; thus, the inline template rule is the only template rule that applies to namespace nodes.
The built-in template rules are processed as if they were imported implicitly in front of the stylesheet and therefore have a lower import priority than all other template rules. Thus, the author can override the built-in template rule by including an explicit template rule.
So, the reported behavior is the result of using the built-in templates - the 1st and 2nd of all three.
This is a good XSLT design pattern for overriding built-in patterns with your own, which will produce an error message every time you invoke, so that the programmer will immediately know that his conversion is "proceeding":
For example , if there is this XML document:
<a> <b> <c>Don't want to see this</c> </b> </a>
and this is handled using this conversion :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="a|b"> <xsl:copy> <xsl:attribute name="name"> <xsl:value-of select="name()"/> </xsl:attribute> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet>
result :
<a name="a"> <b name="b">Don't want to see this</b> </a>
and the programmer will be very confused about how the unwanted text appeared.
However, simply adding this catch-all template will help to avoid such confusion and immediately detect errors :
<xsl:template match="*"> <xsl:message terminate="no"> WARNING: Unmatched element: <xsl:value-of select="name()"/> </xsl:message> <xsl:apply-templates/> </xsl:template>
Now, in addition to the confusing output, the programmer receives a warning that immediately explains the problem :
WARNING: Unmatched element: c
Michael Kay's late addition for XSLT 3.0
In XSLT 3.0, instead of adding a generic rule for a template, you can specify fallback behavior in the xsl:mode declaration. For example, <xsl:mode on-no-match="shallow-skip"/> forces <xsl:mode on-no-match="shallow-skip"/> all non-matching nodes (including text nodes), and <xsl:mode on-no-match="fail"/> treats the mismatch as an error, and <xsl:mode warning-on-no-match="true"/> issues a warning.