You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用XSLT 1.0移除XML未使用命名空间并保留已用命名空间

移除XML中未使用的命名空间(XSLT 1.0实现)

需求说明

加载XML文件时自动移除其中未使用的命名空间,环境要求为XSLT 1.0(Java)。

示例输入XML

<root xmlns:ns1="some_namespace" xmlns:foo="unused_namespace">
  <ns1:a>bla</ns1:a>
  <c xmlns="std_namespace">
    <d>text</d>
  </c>
  <ns2:e xmlns:ns2="another_ns">
    <ns2:f>aaa</ns2:f>
  </ns2:e>
</root>

期望转换结果

<root xmlns:ns1="some_namespace">
  <ns1:a>bla</ns1:a>
  <c xmlns="std_namespace">
    <d>text</d>
  </c>
  <ns2:e xmlns:ns2="another_ns">
    <ns2:f>aaa</ns2:f>
  </ns2:e>
</root>

当前尝试的XSLT及问题

参考相关代码修改后,虽保留了默认命名空间,但已使用的带前缀命名空间被错误移除,转换结果丢失了所有命名空间前缀。

修改后的XSLT代码:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*" priority="-2">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:variable name="vtheElem" select="."/>
            <xsl:for-each select="namespace::*">
                <xsl:variable name="vPrefix" select="name()"/>
                <xsl:if test="
                ($vPrefix = '')
                or
                ($vtheElem/descendant::*
              [(namespace-uri()=current()
             and 
              substring-before(name(),':') = $vPrefix)
             or
              @*[substring-before(name(),':') = $vPrefix]
              ])
      ">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

错误转换结果:

<?xml version="1.0" encoding="UTF-8"?><root>
    <a>bla</a>
    <c xmlns="std_namespace">
        <d>text</d>
    </c>
    <e>
        <f>aaa</f>
    </e>
</root>

解决方案

问题核心在于命名空间使用判断逻辑不完整,未覆盖当前节点本身的命名空间使用场景,且前缀与URI的关联判断不够严谨。修改后的XSLT如下:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>

    <!-- 通用复制模板,优先级最低 -->
    <xsl:template match="node()|@*" priority="-2">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <!-- 元素处理模板 -->
    <xsl:template match="*">
        <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:variable name="currentElem" select="."/>
            <!-- 遍历所有命名空间节点 -->
            <xsl:for-each select="namespace::*">
                <xsl:variable name="nsPrefix" select="name()"/>
                <xsl:variable name="nsUri" select="."/>
                <!-- 判断命名空间是否被使用:
                     1. 是默认命名空间(前缀为空)
                     2. 当前节点使用了该前缀+URI
                     3. 后代节点使用了该前缀+URI
                     4. 当前节点或后代节点的属性使用了该前缀
                -->
                <xsl:if test="
                    $nsPrefix = ''
                    or
                    (substring-before($currentElem/name(), ':') = $nsPrefix 
                     and $currentElem/namespace-uri() = $nsUri)
                    or
                    ($currentElem//*[
                        substring-before(name(), ':') = $nsPrefix 
                        and namespace-uri() = $nsUri
                    ])
                    or
                    ($currentElem//@*[substring-before(name(), ':') = $nsPrefix])
                ">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

修改说明

  1. 补充了当前节点本身的命名空间使用判断,避免遗漏当前节点的前缀命名空间
  2. 明确前缀与URI的对应关系,确保只有匹配的使用场景才保留命名空间
  3. 拆分判断条件,覆盖元素、后代元素、属性的命名空间使用场景,逻辑更清晰

内容的提问来源于stack exchange,提问作者mamayr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 11:17:53