如何移除XML中多余的命名空间前缀声明?
问题
输入XML如下:
<message xmlns="http://www.ns1.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <elem1 id="att1"> <elem2 i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" /> </elem1> </message>
需要通过XSLT转换为指定格式,要求:
- 将
nil属性的前缀从i改为xsi - 仅根节点保留命名空间声明,子节点上的多余命名空间声明必须移除
期望输出:
<?xml version="1.0" encoding="utf-8"?> <message xmlns="http://www.ns1.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <elem1 id="att1"> <elem2 xsi:nil="true"/> </elem1> </message>
尝试了以下XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.ns1.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="i"> <xsl:output method="xml" indent="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="@i:nil"> <xsl:attribute name="xsi:nil"> <xsl:value-of select="." /> </xsl:attribute> </xsl:template> </xsl:stylesheet>
但转换后elem2节点仍保留了多余的xmlns:i声明,不符合要求:
<?xml version="1.0" encoding="utf-8"?> <message xmlns="http://www.ns1.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <elem1 id="att1"> <elem2 xsi:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" /> </elem1> </message>
仅修改样式表能否实现需求?
解决方案
可以实现需求。原样式表仅处理了@i:nil属性的替换,但未处理子节点上的多余命名空间声明。需要新增模板来过滤非根节点的命名空间属性,同时保留根节点的必要声明。
修改后的XSLT如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.ns1.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="i"> <xsl:output method="xml" indent="yes" encoding="utf-8"/> <!-- 基础复制模板:复制所有节点和属性 --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- 将i:nil属性替换为xsi:nil --> <xsl:template match="@i:nil"> <xsl:attribute name="xsi:nil"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> <!-- 保留根节点的命名空间声明 --> <xsl:template match="*[not(parent::node())]/@*[namespace-uri()='http://www.w3.org/2000/xmlns/']" priority="1"/> <!-- 移除所有非根节点的命名空间声明 --> <xsl:template match="*[parent::node()]/@*[namespace-uri()='http://www.w3.org/2000/xmlns/']"/> </xsl:stylesheet>
关键说明:
- 新增的两个模板专门处理命名空间属性(命名空间为
http://www.w3.org/2000/xmlns/的属性):- 第一个模板通过
*[not(parent::node())]匹配根节点,保留其命名空间声明 - 第二个模板过滤所有非根节点上的命名空间声明,直接忽略不输出
- 第一个模板通过
- 原有的属性替换模板正常工作,完成
i:nil到xsi:nil的转换 exclude-result-prefixes="i"确保样式表内部声明的i前缀不会被输出到结果中
使用该样式表转换后,即可得到符合要求的输出,子节点不会保留多余的命名空间声明。
内容的提问来源于stack exchange,提问作者Owen Smith
相关产品推荐
相关产品推荐

