xsltproc不按名称选择元素

时间:2010-10-17 18:41:30

标签: xslt

我正在尝试使用XSLT样式表转换XHTML,但我甚至无法获得匹配任何内容的基本样式表。我确定我错过了一些简单的事情。

这是我的XHTML源文档(没什么大惊喜):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content=
"HTML Tidy for Windows (vers 25 March 2009), see www.w3.org" />
...
</body>
</html>

实际内容并不重要,我将在下面演示。顺便说一下,我很确定该文档是通过tidy -asxml创建的,因此文档格式正确。

我更复杂的XPath表达式没有返回任何结果,所以作为一个完整性测试,我试图使用以下样式表非常简单地转换它:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
    <xsl:template match="/">
        <xsl:text>---[</xsl:text>
        <xsl:for-each select="html">
            <xsl:text>Found HTML element.</xsl:text>
        </xsl:for-each>
        <xsl:text>]---</xsl:text>
    </xsl:template>
</xsl:stylesheet>

转换是通过xsltproc --nonet stylesheet.xsl input.html完成的,输出是:“--- [] ---”(即,它没有找到html的子元素)。但是,如果我将for-each部分更改为:

<xsl:for-each select="*">
    <xsl:value-of select="name()"/>
</xsl:for-each>

然后我得到“--- [html] ---”。同样地,如果我使用for-each select="*/*",我会像我期望的那样得到“--- [headbody] ---”。

为什么它可以通过*找到子元素(name()给出正确的名称)但是它不会直接使用元素名称找到它?

3 个答案:

答案 0 :(得分:6)

源XML中的html元素定义了命名空间。您必须将其包含在匹配表达式中,并在xsl:stylesheet元素中引用它:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:html="http://www.w3.org/1999/xhtml">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
    <xsl:template match="/">
        <xsl:text>---[</xsl:text>
        <xsl:for-each select="html:html">
            <xsl:text>Found HTML element.</xsl:text>
        </xsl:for-each>
        <xsl:text>]---</xsl:text>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:4)

更改样式表
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
        <xsl:text>---[</xsl:text> 
        <xsl:for-each select="html"> 
            <xsl:text>Found HTML element.</xsl:text> 
        </xsl:for-each> 
        <xsl:text>]---</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://www.w3.org/1999/xhtml"
> 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
        <xsl:text>---[</xsl:text> 
        <xsl:for-each select="x:html"> 
            <xsl:text>Found HTML element.</xsl:text> 
        </xsl:for-each> 
        <xsl:text>]---</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

<强>解释

XML文档声明了一个默认命名空间:"http://www.w3.org/1999/xhtml",并且从声明此默认命名空间的顶部元素下降的所有未加前缀的节点都属于此命名空间。

另一方面,在XPath中,任何未加前缀的名称都被认为属于“无命名空间”。

因此,<xsl:for-each select="html">指令将选择并将其主体应用于属于“无命名空间”的所有html元素 - 并且文档中没有这样的元素 - 唯一{{1}元素确实属于xhtml命名空间。

<强>解决方案

属于默认命名空间的名称不能以前缀为参考。因此,我们需要将前缀绑定到元素所属的命名空间。如果此前缀为html,那么我们可以使用"x:"引用任何此类元素带前缀

答案 2 :(得分:0)

没有声明命名空间的变通方法,以便样式表接受任何命名空间:

<xsl:template match="*[name()='html']" >