xsl:template match attribute: how related to defau

2019-05-11 16:20发布

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?

2条回答
smile是对你的礼貌
2楼-- · 2019-05-11 16:47

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:

if the QName does not have a prefix, then the namespace URI is null.

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:

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:x="http://test.com" exclude-result-prefixes="x">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>

        <xsl:template match="/">
            <root>
                <xsl:apply-templates/>
            </root>
        </xsl:template>

        <xsl:template match="x:content">
            <w>x</w>
        </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document with default namespace:

<root xmlns="http://test.com">
    <content>xxx</content>
</root>

produces the wanted, correct result:

<root>
   <w>x</w>
</root>
查看更多
别忘想泡老子
3楼-- · 2019-05-11 17:04

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 the http://test.com namespace (by way of the namespace declaration on its parent). Therefore, the default templates take over.

查看更多
登录 后发表回答