如何将XML中所有命名空间声明迁移至根节点?
可行,以下是实现方案
完全可以实现将所有命名空间声明移至根节点的需求,同时保留你现有XSLT模板的功能。核心思路是先收集文档中所有的命名空间,再在根节点统一输出这些命名空间,处理子元素时忽略它们自带的命名空间声明。
源XML示例
<top> <middle xmlns:first="http://test.com"> <inner xmlns:second="http://somthing.com"> Hello </inner> </middle> </top>
期望输出XML
<top xmlns:first="http://test.com" xmlns:second="http://somthing.com"> <middle> <inner> Hello </inner> </middle> </top>
实现的XSLT代码(可与现有模板整合)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 收集所有命名空间,存入变量(排除XSLT自身命名空间) --> <xsl:variable name="all-namespaces" as="element()*"> <xsl:for-each select="//namespace::*[not(. = 'http://www.w3.org/1999/XSL/Transform') and not(local-name()='')]"> <xsl:namespace name="{local-name()}"><xsl:value-of select="."/></xsl:namespace> </xsl:for-each> </xsl:variable> <!-- 根节点模板:输出根元素+所有收集到的命名空间 --> <xsl:template match="/"> <xsl:element name="{name(/*)}"> <xsl:copy-of select="$all-namespaces"/> <xsl:apply-templates select="/*/*"/> </xsl:element> </xsl:template> <!-- 通用元素模板:复制元素结构,但不复制命名空间属性 --> <xsl:template match="*"> <xsl:element name="{name()}"> <!-- 复制除命名空间声明外的其他属性 --> <xsl:copy-of select="@*[not(namespace-uri()='http://www.w3.org/2000/xmlns/')]"/> <!-- 处理子节点,自动调用现有自定义模板 --> <xsl:apply-templates/> </xsl:element> </xsl:template> <!-- 在这里添加你的其他自定义模板 --> <!-- 示例:修改inner元素文本的模板 --> <!-- <xsl:template match="inner"> <inner> <xsl:text>Modified Hello</xsl:text> </inner> </xsl:template> --> </xsl:stylesheet>
整合现有模板的注意事项
- 自定义模板的匹配模式要比通用元素模板更具体,或者通过
priority属性设置更高优先级,确保原有逻辑正常执行 - 如果使用XSLT 1.0,需要用
exsl:node-set扩展函数处理节点集变量,XSLT 2.0及以上版本可直接使用上述代码 - 通用模板会自动过滤所有命名空间属性,避免子元素重复输出命名空间声明
内容的提问来源于stack exchange,提问作者Koolan
相关产品推荐
相关产品推荐

