Working on a larger transform, but was able to replicate this in a mock-up. If I use the “mode” attribute in my XSLT template, the result is just the raw text (without markup) of the original XML that is supposed to be transformed. If I instead use the “name” attribute, it transforms as expected.
XML
<Parent>
<ParentCon>Parent Content</ParentCon>
<Child>
<ChildCon>Child Content</ChildCon>
<Grandchild>Some Grandchild Content</Grandchild>
</Child>
</Parent>
XSLT (with mode attribute)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Parent" mode="xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Output (with mode attribute)
<?xml version="1.0" encoding="UTF-8"?>
Parent Content
Child Content
Some Grandchild Content
XSLT (with name attribute)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Parent" name="xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Output (with name attribute)
<?xml version="1.0" encoding="UTF-8"?><ExportParent><ExportChild/></ExportParent>
Googling suggests that name and mode are functionally the same, except mode allows for re-use.
I expected the output to be the same with both attributes.
1
The problem with your template with mode
attribute is that it is never applied, and the entire transformation is performed using only the built-in template rules.
The XSLT 1.0 specification states that:
if an
xsl:apply-templates
element does not have amode
attribute, then
it applies only to those template rules fromxsl:template
elements
that do not have amode
attribute.
There is no xsl:apply-templates
instruction in your XSLT, and the built-in template rule applies templates without mode
.
The result of processing an XML using only the built-in template rules is a copy of all the text nodes in the input document.
The name of a template plays no role unless you are calling the template by its name.
See:
https://www.w3.org/TR/1999/REC-xslt-19991116/#modes
https://www.w3.org/TR/1999/REC-xslt-19991116/#built-in-rule
https://www.w3.org/TR/1999/REC-xslt-19991116/#named-templates
Default processing applies templates that are not in a mode. There are built-in templates that fire, which apply-templates to child nodes, and a default template for text()
that returns the text. So, when those default templates match, it just spits out the text()
.
If you wanted to get your expected output you could create a template matching on the root node /
and then inside that template apply-templates in the “xyz” mode and it would match on Parent
and apply that template in that mode:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates mode="xyz"/>
</xsl:template>
<xsl:template match="Parent" mode="xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
You need to apply templates in that mode to use the templates in that mode. XSLT 3.0 also allows you to declare the default mode:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" default-mode="xyz">
<xsl:template match="Parent" mode="xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Example online fiddle.