Reputation: 110
I have an XML file like so:
<text>
<a>foo1</a>
<a><b>foo2</b></a>
</text>
I have an XSL file designed to process <a>
and <a><b>
differently with templates 1 and 2:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- t1 -->
<xsl:template match="a">
<xsl:element name="keep">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- t2 -->
<xsl:template match="a/b" />
</xsl:stylesheet>
I expected that this would produce:
<text>
<keep>foo1</keep>
</text>
Because t2 should match and 'ignore' <a><b>foo2</a></b>
and I thought that it would take precedence over t1 (both t1 and t2 match <a><b>
but t2 is simply later in the XSL). But the output is in fact:
<text>
<keep>foo1</keep>
<keep>foo2</keep>
</text>
In fact if I take t2 away the output is the same, so clearly it is not even matching <a><b>
. I must be missing something: please can anyone help?
Upvotes: 1
Views: 1124
Reputation: 22617
What you are looking for is
<xsl:template match="a[b]" />
a template that matches a
elements if they have a child element called b
.
A template match like
<xsl:template match="a/b" />
does not match a
elements, it matches b
elements that have an a
element as their parent. But in your original stylesheet, the XSLT processor is never prompted to find a matching template for b
elements, that's why the code contained in this template (none) is never executed.
With this change, the output is
<?xml version="1.0" encoding="UTF-8"?>
<text>
<keep>foo1</keep>
</text>
As you can see, it's almost the output you expected. With your XSLT processor, MSXSL, the empty line likely is not even there, because MSXSL strips the tree of whitespace-only nodes. But to have your stylesheet produce consistent results on any processor, the info below is still useful.
To remove the empty line in the output, add xsl:strip-space
as a top-level element. Also, save yourself the trouble of typing xsl:element name=...
if the element name is known beforehand. The whole stylesheet:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- t1 -->
<xsl:template match="a">
<keep>
<xsl:value-of select="."/>
</keep>
</xsl:template>
<!-- t2 -->
<xsl:template match="a[b]" />
</xsl:stylesheet>
Upvotes: 1