Reputation: 81
This questions is simpler to describe by example rather than as text.
With the following XML
<?xml version="1.0" encoding="UTF-8"?>
<tests>
<test>1</test>
<test>2</test>
</tests>
If I run the following XSLT3
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
expand-text="true"
version="3.0">
<xsl:output method="xml" />
<xsl:mode on-no-match="shallow-copy" />
<!--<xsl:mode name="test" on-no-match="shallow-copy"/>-->
<xsl:template match="/">
<mytests>
<xsl:apply-templates/>
<xsl:apply-templates mode="test"/>
</mytests>
</xsl:template>
<xsl:template match="tests" mode="test">
<modetest>
<xsl:apply-templates mode="#current"/>
</modetest>
</xsl:template>
</xsl:stylesheet>
I get following output in Saxon 9
<?xml version="1.0" encoding="UTF-8"?>
<mytests>
<tests>
<test>1</test>
<test>2</test>
</tests>
<modetest>
1
2
</modetest>
</mytests>
You can see that when the mode "test" is being used we do not get the test element being output, only that elements content. There is not template for the element "test" with a mode of "test".
I would have guessed that as there is no match the on-no-match="shallow-copy" would have kicked in from the xsl:mode with no name attribute? My guess was that a no named xsl:mode would apply to all no matches even if a mode was is in effect (unless another xsl:mode is defined with a name that matches the current mode). If you uncomment the xsl:mode name="test" on-no-match="shallow-copy" then everything works as expected (so no workaround required thanks) but this means that in an XSLT with lots and lots of modes in apply-templates, I need to define lots and lots of named xsl:modes just to get the identity template behavior.
Can anyone point out if I am doing something wrong or if this is behaving as per the w3C specification?
Upvotes: 2
Views: 1072
Reputation: 163458
"My guess was that a no named xsl:mode would apply to all no matches even if a mode was is in effect"
Sorry, your guess would be wrong. Think of it this way: there is a mode whose name is #unnamed
, and any xsl:template
, xsl:apply-templates
, or xsl:mode
element with no @mode
attribute defaults to mode="#unnamed"
. (That's an approximation, it gets more complicated when default-mode
is specified, but that's the basic concept.)
There's no way of defining the properties of lots of modes "in bulk", you need one xsl:mode
declaration per mode.
Upvotes: 3
Reputation: 167696
The default, built-in processing for any mode is text-only-copy
, see https://www.w3.org/TR/xslt-30/#modes "If a mode name is used (for example in an xsl:template declaration or an xsl:apply-templates instruction) and no declaration of that mode appears in the stylesheet, the mode is implicitly declared with default properties" and https://www.w3.org/TR/xslt-30/#built-in-rule
There are six sets of built-in template rules available. The set that is chosen is a property of the mode selected by the
xsl:apply-templates
instruction. This property is set using theon-no-match
attribute of the xsl:mode declaration, which takes one of the six valuesdeep-copy
,shallow-copy
,deep-skip
,shallow-skip
,text-only-copy
, orfail
, the default beingtext-only-copy
.
The built-in default processing in XSLT 2 or 1 it not different.
If having to declare the identity transformation separately with separate xsl:mode
declarations appears to be too cumbersome, you can of course also write a template
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@*" mode="#current"/>
<xsl:apply-templates mode="#current"/>
</xsl:copy>
</xsl:template>
https://www.w3.org/TR/xslt-30/#using-modes
Upvotes: 1