如何在XSL的for-each标签中访问包含xmlns的所有属性?
How to Access Namespace Declaration Attributes (xmlns:*) in XSLT
你遇到的问题很典型——XML里的xmlns:*(包括无后缀的xmlns)不是常规属性,而是命名空间声明,XPath的@*轴只会选中普通属性,所以它们不会被遍历到。要获取这些"属性",需要用专门的XPath轴来访问命名空间节点。
解决方案:使用namespace::轴访问命名空间声明
在XSLT 2.0中,你可以通过namespace::轴获取当前节点上的所有命名空间节点,再将它们格式化成你需要的<name>和<value>结构。
修改后的XSLT代码
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:template match="/"> <!-- 遍历所有常规属性 --> <xsl:for-each select="/schema/@*"> <name><xsl:value-of select="name()"/></name> <value><xsl:value-of select="."/></value> </xsl:for-each> <!-- 遍历所有命名空间声明(排除XML自带的默认xml命名空间) --> <xsl:for-each select="/schema/namespace::*[not(local-name()='xml')]"> <name> <!-- 处理默认命名空间(无前缀的情况,即xmlns="xxx") --> <xsl:choose> <xsl:when test="local-name() = ''">xmlns</xsl:when> <xsl:otherwise>xmlns:<xsl:value-of select="local-name()"/></xsl:otherwise> </xsl:choose> </name> <value><xsl:value-of select="."/></value> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码说明
- 常规属性遍历:保留你原有的
@*逻辑,处理a="a"和something:b="b"这类普通属性。 - 命名空间节点遍历:
namespace::*轴选中当前节点(这里是<schema>)上的所有命名空间节点。not(local-name()='xml')过滤掉XML规范自带的xml命名空间(它的URI是http://www.w3.org/XML/1998/namespace,通常不需要输出)。- 针对默认命名空间(无前缀,即
xmlns="xxx"),输出<name>xmlns</name>;带前缀的命名空间则输出<name>xmlns:前缀</name>,和XML中的写法完全一致。
最终转换结果
用这段XSLT处理你的XML,会得到完整的输出:
<name>a</name><value>a</value> <name>something:b</name><value>b</value> <name>xmlns:c</name><value>c</value>
为什么@*选不到命名空间声明?
XML解析器会把xmlns:*和xmlns识别为命名空间绑定信息,而非普通属性。在XPath数据模型中,它们属于单独的namespace::轴,和attribute::(简写@)轴是完全分开的,所以@*不会包含这些节点。
内容的提问来源于stack exchange,提问作者user3429660
相关产品推荐
相关产品推荐

