I encountered a peculiar difference in xslt behavior when the root element has a default namespace attribute as opposed to when it does not.
I am wondering why this difference occurs.
The XML input is
<root>
<content>xxx</content>
</root>
When the following transformation is applied
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="content">
<w>x</w>
</xsl:template>
</xsl:stylesheet>
the result is the expected
<?xml version="1.0" encoding="UTF-8"?>
<root>
<w>x</w>
</root>
But when the same transformation is applied to
<root xmlns="http://test.com">
<content>xxx</content>
</root>
the result is different and based on the application of just default templates (which effectively output the text node value 'xxx'):
<?xml version="1.0" encoding="UTF-8"?>
<root>xxx</root>
Addition
When this is the expected behavior in this case, then what match attribute value is needed to match the content
element in the second case?
This is the most FAQ in XPath / XSLT.
An unprefixed element name is treated by XPath as belonging to "no namespace".
The W3C Xpath specification says:
Therefore, in a document with a default namespace a refernce to an element with unprefixed name (say "someName") selects nothing, because there isn't any element in "no namespace" in the XML document, but
someName
means an element with name "someName", belonging to "no namespace".The Solution:
If we want to select an element by name, we must prefix that name and the prefix must be associated with the default namespace.
This transformation:
when applied on the provided XML document with default namespace:
produces the wanted, correct result:
so what exactly is your question? If you're simply looking for an explanation, following is a brief one. What you're observing is the proper behavior according to the specification. When you put a namespace on something, the parser essentially treats it as a different element entirely (than an element of the same name but no namespace). Therefore, in the second situation, when you say
<xsl:template match="content">
, it doesn't match the<content>
element in the XML file because it falls under thehttp://test.com
namespace (by way of the namespace declaration on its parent). Therefore, the default templates take over.