XSLT和XHTML输出的默认命名空间

4

我将尝试解释XSLT如何处理命名空间前缀,并提供以下示例:XML:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
    xmlns:xhtml="http://www.w3.org/1999/xhtml" 
    xmlns:zno="http://feed.zinio.com/atom" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.w3.org/2005/Atom 
                      http://www.w3.org/1999/xhtml 
                      http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd
                      http://feed.zinio.com/atom" >
    <entry>
        <author>
            <name>By Sheila F. Buckmaster</name>
        </author>
        <category xml:lang="en" term="TRAVEL"/>
        <content>
            <h2 class="hl2">One of the world’s most entrancing cities becomes even more captivating when costumed revelers fill its tiny streets and grand piazzas during Carnevale. It is here that a star of the silent screen comes alive, antics and all</h2>
            <div class="byline">By Sheila F. Buckmaster</div>
        </content>
   </entry>
</feed>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
                           xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                           xmlns:user="urn:my-scripts"
                           xmlns:x="http://www.w3.org/1999/xhtml" 
                           xmlns:AP="http://www.w3.org/2005/Atom"
                           exclude-result-prefixes="xslt msxsl user">

    <xslt:output method="xml" indent="yes"/>
    <xslt:template match="/">
        <xslt:apply-templates select="/AP:feed//AP:entry"/>
    </xslt:template>

    <xslt:template match="AP:entry">
        <xslt:text>Hello from entry</xslt:text>
        <xslt:apply-templates select="AP:content"/>
    </xslt:template>

    <xslt:template match="AP:content">
        <xslt:text>Hello from content</xslt:text>
        <xslt:apply-templates select="x:div[@class='byline']"/>
    </xslt:template>

    <xslt:template match="x:div[@class='byline']">
        <xslt:copy-of select="."/>
    </xslt:template>
</xslt:stylesheet>

我想要做的是访问我的“div”。由于我明确指定了命名空间,因此“Entry”和“Content”模板可以正常工作。但是当我尝试使用XHTML前缀(在我的情况下为“x”)访问“div”时,XSLT无法看到它。只有当我在“div”元素前加上“AP”命名空间前缀时,它才能正常工作:

    <xslt:template match="AP:content">
        <xslt:text>Hello from content</xslt:text>
        <xslt:apply-templates select="AP:div[@class='byline']"/>
    </xslt:template>

    <xslt:template match="AP:div[@class='byline']">
        <xslt:copy-of select="."/>
    </xslt:template>

但是我觉得这不对,因为DIV元素应该在XHTML命名空间中。我做错了什么?
2个回答

2
Atom源代码在根元素上声明了Atom命名空间,但没有使用命名空间前缀。因为未显式声明XHTML命名空间,所以
和其他XHTML元素继承了Atom命名空间。
如果您希望将XHTML元素绑定到XHTML命名空间,则需要将Atom feed中的
更改为:
<div xmlns:xhtml="http://www.w3.org/1999/xhtml" class="byline">By Sheila F. Buckmaster</div>

或者:

<xhtml:div class="byline">By Sheila F. Buckmaster</xhtml:div>

如果您希望保持Atom源的不变,并且仍想生成XHTML元素,则需要调整样式表以匹配AP:div,然后构建输出中的XHTML元素。
例如,修改您的样式表,我会在名为xhtml的模式中apply-templates到匹配的AP:div。该模式中有一个匹配任何元素的模板(因此也适用于AP:h2),使用匹配元素的local-name()来构建XHTML元素。
<?xml version="1.0" encoding="UTF-8"?>
<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:user="urn:my-scripts"
    xmlns:x="http://www.w3.org/1999/xhtml" 
    xmlns:AP="http://www.w3.org/2005/Atom"
    exclude-result-prefixes="xslt msxsl user">

    <xslt:output method="xml" indent="yes"/>
    <xslt:template match="/">
        <xslt:apply-templates select="/AP:feed//AP:entry"/>
    </xslt:template>

    <xslt:template match="AP:entry">
        <xslt:text>Hello from entry</xslt:text>
        <xslt:apply-templates select="AP:content"/>
    </xslt:template>

    <xslt:template match="AP:content">
        <xslt:text>Hello from content</xslt:text>
        <xslt:apply-templates select="AP:div[@class='byline']"/>
    </xslt:template>

    <xslt:template match="AP:div[@class='byline']">
        <xslt:apply-templates select="." mode="xhtml"/>
    </xslt:template>

    <!--create an XHTML element with the same name as the context element -->
    <xslt:template match="*" mode="xhtml">
        <xslt:element name="{local-name()}" namespace="http://www.w3.org/1999/xhtml">
            <xslt:apply-templates select="@*|node()" mode="xhtml"/>
        </xslt:element>
    </xslt:template>

    <!--attributes, comments, and processing-instructions simply copied -->
    <xslt:template match="@*|text()|comment()|processing-instruction()">
        <xslt:copy-of select="."/>
    </xslt:template>

</xslt:stylesheet>

由于我无法更改输入的XML,所以我喜欢你的第二个解决方案。但是,我有两个评论:
  • apply-templates不应包含模式“xhtml”。这样属性就会直接复制到元素体中。因此,我只添加了单独的<code><xslt:apply-templates select="@*"/></code>。
- Pavel Dudka
你的第二个解决方案还有一个问题,就是它会在输出的 div 标签中添加 ns0: 前缀(<ns0:div ....)。有没有什么方法可以去掉这个前缀? - Pavel Dudka
我假设您希望在XHTML输出中包含@class。显然,您可以根据自己的输出需求进行修改。希望您理解它为什么会出现这种行为以及如何控制它。 - Mads Hansen
命名空间前缀(对于XML解析器)并不重要。你想要什么前缀呢?假设你想要 <x:div>,你可以将元素@name更改为 name="x:{local-name()}" - Mads Hansen
如果对于 XML 解析器来说无关紧要,那我就没问题。这个 XHTML 的东西对我来说很新,所以我有点担心我不理解的额外标记。非常感谢你的帮助。 - Pavel Dudka
嗯,应该是<div xmlns="http://www.w3.org/1999/xhtml">By Sheila F. Buckmaster<div>,即在xmlns属性上不加:xhtml部分吗?否则,xmlns:xhtml属性就没有效果——它只是声明在节点的范围内,以xhtml:为前缀的名称属于XHTML命名空间。但是,在其中没有元素或属性节点,只有一个文本节点(“By Sheila F. Buckmaster”)。因此,如果您的意图是使div元素属于XHTML命名空间,则应省略xmlns:xhtml属性末尾的:xhtml。我说的对吗? - Armen Michaeli

2
在你的xml中,div需要是xhtml:div。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接