当缺少命名空间前缀时,XSLT不解析XML



我正在编写第一个转换XML文件的XSLT代码。

下面的示例代码只是为了解释这里的问题。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn.abc.xyz" xmlns:ns2="abc:cde">
<xsl:template match="/catalog">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
<th>Price</th>      
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
<td><xsl:value-of select="price"/></td>        
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

当所有名称空间在输入XML中都有前缀时,上面的代码工作得很好。但是当XML中缺少命名空间前缀时,即执行只显示没有标记名称的XML内容,则无法工作。

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<catalog  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn.abc.xyz" xmlns:ns2="abc:cde">
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>

以上XML的输出:标题艺人价格

与前缀:

<catalog  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abc="urn.abc.xyz" xmlns:ns2="abc:cde">

没有前缀

<catalog  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn.abc.xyz" xmlns:ns2="abc:cde">

如果我运行没有名称空间前缀(abc)的XSL然后输出如下所示

帝国滑剧鲍勃·迪伦美国哥伦比亚10.90 1985

谁能帮助为什么我的XSL不工作时,名称空间前缀是空的?在我的XSL中需要做哪些更改,以便即使缺少名称空间前缀也能正常工作。

不带前缀的命名空间声明定义了一个默认命名空间,并将所有未带前缀的元素置于该命名空间的声明范围内。

为了在样式表中处理这些元素,必须声明相同的名称空间,为其分配一个前缀,并将该前缀用于源XML中的所有无前缀元素。

例如,如果输入的XML是:

<catalog xmlns="urn.abc.xyz">
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>

那么你的样式表需要是:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:abc="urn.abc.xyz"
exclude-result-prefixes="abc">
<xsl:template match="/abc:catalog">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
<th>Price</th>      
</tr>
<xsl:for-each select="abc:cd">
<tr>
<td><xsl:value-of select="abc:title"/></td>
<td><xsl:value-of select="abc:artist"/></td>
<td><xsl:value-of select="abc:price"/></td>        
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

(你可以使用任何你想要的前缀)

但是,这个样式表不适合处理元素为no-namespace的输入:

<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>

从技术上讲,可以构造一个样式表,忽略名称空间,只使用元素的本地名称来处理这两个xml。但是,除非绝对必要,否则不建议这样做。假设名称空间的存在是有原因的,忽略它们可能会导致不正确的结果。

还请注意,使用前缀的名称空间声明,例如示例中的xmlns:ns2="abc:cde",仅应用于具有相同前缀的节点。如果没有这样的节点,这样的声明就没有效果,而且是完全多余的(与你的问题无关)。

在XSLT 1.0中,如果源文档中的元素位于名称空间中,则必须在XSLT中的XPath表达式中使用名称空间前缀。

在源文档中声明" run .abc.xyz"作为默认名称空间URI。(顺便说一句,"urn.abc.xyz"不是真正合适的名称空间URI;它应该是一个绝对URI,包括一个URI方案,例如:urn:abc.xyz;或者别的什么,但这不是你的问题)。

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn.abc.xyz">
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>

(注:我删除了未使用的XSLT和"ns2"命名空间声明(因为它们没有在文件的任何地方使用)。

在XSLT中,您有一个XPath匹配表达式=/catalog的模板,但是因为catalog没有名称空间前缀,所以它只匹配没有名称空间中的catalog元素。要匹配urn.abc.xyz名称空间中的catalog元素,您需要首先将名称空间前缀(可以是任何东西,例如my-namespace)与urn.abc.xyz名称空间URI相关联,然后使用XPath表达式"/my-namespace:catalog"在模板的match属性中。要将urn.abc.xyz名称空间URI绑定到前缀my-namespace,请向样式表元素添加名称空间声明:xmlns:my-namespace="urn.abc.xyz"

然后在模板中,您的xsl:for-each语句将使用表达式my-namespace:cd引用子元素,类似地,您需要使用my-namespace:title等来引用cd元素的子元素。

最新更新