移除子节点多余命名空间:XML嵌套至ns0:OperationBody问题
解决方案:消除嵌套XML中的多余命名空间并满足转义要求
问题分析
当前XSLT存在两个核心问题导致多余命名空间输出:
- 遍历
namespace::*时包含了从父元素继承的命名空间节点,导致子元素重复输出祖先已声明的命名空间(比如commonProvide元素上冗余的xmlns:ns1)。 - 硬编码了命名空间值,与输入XML中的实际命名空间(
GlobalInteraction.xsdobjects)不符,且强制在根元素输出固定命名空间。
修正后的XSLT代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="serviceBusiness.xsdobjects.extload.services.classic.bt" xmlns:ns1="GlobalInteraction.xsdobjects" xmlns:commonProvide="commonentities.xsdobjects.extload" exclude-result-prefixes="xsl ns1 commonProvide"> <!-- 主模板:生成ns0:OperationBody容器 --> <xsl:template match="/"> <ns0:OperationBody> <xsl:apply-templates mode="escape"/> </ns0:OperationBody> </xsl:template> <!-- 元素转义模板:仅输出元素自身声明的命名空间,避免继承的冗余命名空间 --> <xsl:template match="*" mode="escape"> <!-- 输出转义的起始标签左括号 --> <xsl:text><</xsl:text> <xsl:value-of select="name()"/> <!-- 输出元素自身直接声明的命名空间(排除继承的) --> <xsl:for-each select="namespace::*[not(. = ancestor::*/namespace::*[name()=current()/name()])]"> <xsl:if test="name() != ''"> <xsl:text> xmlns:</xsl:text> <xsl:value-of select="name()"/> <xsl:text>="</xsl:text> <xsl:value-of select="."/> <xsl:text>"</xsl:text> </xsl:if> <!-- 处理默认命名空间 --> <xsl:if test="name() = ''"> <xsl:text> xmlns="</xsl:text> <xsl:value-of select="."/> <xsl:text>"</xsl:text> </xsl:if> </xsl:for-each> <!-- 结束起始标签 --> <xsl:text disable-output-escaping="yes">></xsl:text> <!-- 递归处理子节点 --> <xsl:apply-templates select="node()" mode="escape"/> <!-- 输出转义的结束标签 --> <xsl:text></</xsl:text> <xsl:value-of select="name()"/> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> <!-- 文本节点转义模板 --> <xsl:template match="text()" mode="escape"> <xsl:call-template name="escape-xml"> <xsl:with-param name="text" select="."/> </xsl:call-template> </xsl:template> <!-- 通用XML转义模板 --> <xsl:template name="escape-xml"> <xsl:param name="text"/> <xsl:if test="$text != ''"> <xsl:variable name="head" select="substring($text, 1, 1)"/> <xsl:variable name="tail" select="substring($text, 2)"/> <xsl:choose> <xsl:when test="$head = '&'">&amp;</xsl:when> <xsl:when test="$head = '<'">&lt;</xsl:when> <xsl:when test="$head = '>'"> <xsl:value-of select="'&gt;'" disable-output-escaping="yes"/> </xsl:when> <xsl:when test="$head = '"'">&quot;</xsl:when> <xsl:when test="$head = '''">&apos;</xsl:when> <xsl:otherwise> <xsl:value-of select="$head"/> </xsl:otherwise> </xsl:choose> <xsl:call-template name="escape-xml"> <xsl:with-param name="text" select="$tail"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
关键修改说明
- 移除硬编码命名空间:不再固定输出预设的命名空间变量,而是通过
namespace::*动态获取元素自身声明的命名空间,确保与输入XML完全一致。 - 过滤继承的命名空间:通过
not(. = ancestor::*/namespace::*[name()=current()/name()])判断逻辑,只输出当前元素直接声明、且未在祖先元素中出现过的命名空间,彻底消除冗余。 - 修正前缀绑定:将XSLT中
ns1的命名空间绑定改为输入XML中的GlobalInteraction.xsdobjects,匹配原始输入的命名空间结构。
预期输出
修正后的输出将严格保留输入XML中原本声明的命名空间,不会出现多余的xmlns:ns1在commonProvide元素上,同时完全满足起始标签转义为<、结束标签保持>的要求。
内容的提问来源于stack exchange,提问作者sunil
相关产品推荐
相关产品推荐

