使用XSL提取多命名空间XML的NewDataSet段异常求助
解决带命名空间XML提取无命名空间NewDataSet的问题
这种情况我碰到过好多次,核心问题基本都是命名空间的处理不到位——带命名空间的XML节点,在XSL中如果没有正确声明、引用,要么匹配不到目标节点,要么抽取出的结果还带着残留的命名空间。我给你梳理下关键步骤和示例代码:
先明确问题场景(假设你的原XML结构)
比如你的源XML是带命名空间的,可能是带前缀的默认命名空间:
<!-- 带前缀命名空间的示例 --> <root xmlns:data="http://your-namespace-uri.com"> <data:OtherData>无关内容</data:OtherData> <data:NewDataSet> <data:Table> <data:ID>1</data:ID> <data:Name>Test</data:Name> </data:Table> </data:NewDataSet> </root> <!-- 或者是默认命名空间(不带前缀)的示例 --> <root xmlns="http://your-namespace-uri.com"> <OtherData>无关内容</OtherData> <NewDataSet> <Table> <ID>1</ID> <Name>Test</Name> </Table> </NewDataSet> </root>
正确的XSL处理代码
不管是带前缀还是默认命名空间,核心思路都是:在XSL中声明对应命名空间,用前缀匹配源节点,然后创建不带命名空间的新节点输出。
针对带前缀命名空间的XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:data="http://your-namespace-uri.com" <!-- 必须和源XML的命名空间URI完全一致 --> exclude-result-prefixes="data"> <!-- 排除这个前缀,避免输出到结果XML --> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 匹配根节点,定位到目标NewDataSet --> <xsl:template match="/"> <xsl:apply-templates select="root/data:NewDataSet"/> </xsl:template> <!-- 把带命名空间的NewDataSet转成无命名空间的 --> <xsl:template match="data:NewDataSet"> <NewDataSet> <xsl:apply-templates/> </NewDataSet> </xsl:template> <!-- 处理NewDataSet下的所有子节点,统一去掉命名空间 --> <xsl:template match="data:*"> <xsl:element name="{local-name()}"> <xsl:apply-templates select="@* | node()"/> </xsl:element> </xsl:template> <!-- 处理属性(如果有带命名空间的属性) --> <xsl:template match="data:@*"> <xsl:attribute name="{local-name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> <!-- 复制文本、注释等非元素节点 --> <xsl:template match="text() | comment() | processing-instruction()"> <xsl:copy/> </xsl:template> </xsl:stylesheet>
针对默认命名空间的XSL:
默认命名空间的源XML没有前缀,但节点依然属于该命名空间,所以XSL里需要给这个命名空间加一个临时前缀来匹配:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:data="http://your-namespace-uri.com" <!-- 给默认命名空间加前缀 --> exclude-result-prefixes="data"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:template match="/"> <xsl:apply-templates select="data:root/data:NewDataSet"/> </xsl:template> <!-- 后续模板和上面带前缀的示例完全一致 --> <xsl:template match="data:NewDataSet"> <NewDataSet> <xsl:apply-templates/> </NewDataSet> </xsl:template> <xsl:template match="data:*"> <xsl:element name="{local-name()}"> <xsl:apply-templates select="@* | node()"/> </xsl:element> </xsl:template> <!-- ... 其他模板同上 ... --> </xsl:stylesheet>
关键注意点
- 命名空间URI必须完全一致:XSL里声明的命名空间URI要和源XML的完全一样,哪怕多一个空格都匹配不到节点。
- 不要直接用不带前缀的节点名匹配:比如源XML里的
data:NewDataSet,你直接写match="NewDataSet"是匹配不到的——带命名空间的节点和不带命名空间的节点在XML里是完全不同的节点。 - 用
local-name()剥离前缀:通过{local-name()}获取节点的本地名称,创建新的无命名空间元素。
内容的提问来源于stack exchange,提问作者Luis Ortiz
相关产品推荐
相关产品推荐

