如何从 XML 元素中删除一个特定的命名空间
Posted
技术标签:
【中文标题】如何从 XML 元素中删除一个特定的命名空间【英文标题】:How to remove one specific namespace from XML element 【发布时间】:2018-12-01 20:00:41 【问题描述】:我已经寻找过这个具体案例,但没有找到。我有这个 XML,除了这三个元素之外还有其他元素,但它们无关紧要。相关元素附有两个命名空间。我想删除 xmlns:two 所以在输出中只有第一个 xmlns 存在。
<?xml version="1.0" encoding="UTF-8"?>
<Header>
<one:id xmlns:one="http://x.com/xsd/so"
xmlns:two="http://x.com/xsd/woa.xsd">555</one:id>
<one:protocolVersion xmlns:one="http://x.com/xsd/so"
xmlns:two="http://x.com/xsd/woa.xsd">2.0</one:protocolVersion>
<one:userId xmlns:one="http://x.com/xsd/so"
xmlns:two="http://x.com/xsd/woa.xsd">12345</one:userId>
</Header>
现在我想要的是删除 xmlns:two
<?xml version="1.0" encoding="UTF-8"?>
<Header>
<one:id xmlns:one="http://x.com/xsd/so">555</one:id>
<one:protocolVersion xmlns:one="http://x.com/xsd/so">2.0</one:protocolVersion>
<one:userId xmlns:one="http://x.com/xsd/so">12345</one:userId>
</Header>
我尝试过类似的方法,但它删除了错误的命名空间。它删除了作为前缀的相同命名空间。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:two="http://x.com/xsd/woa.xsd"
xmlns:one="http://x.com/xsd/so">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="one:id">
<xsl:element name="local-name()">
<xsl:copy-of select="namespace::*[not(. = namespace-uri(..))]"/>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
【问题讨论】:
请注意,您的 XML 格式不正确。您有一个开始的<one:id>
标记,但有一个结束的</xro:id>
标记。
谢谢@TimC,我修好了。
【参考方案1】:
有很多事情会阻止它产生您所描述的结果:
在这里,您只复制了元素不使用的命名空间,而不是它使用的命名空间:
<xsl:copy-of select="namespace::*[not(. = namespace-uri(..))]"/>
在这里,您在 null 命名空间(无命名空间)中创建一个元素:
<xsl:element name="local-name()">
您已在 XSLT 样式表的根元素上声明了 one
和 two
命名空间,这意味着它们将包含在输出文档的根元素中。
为了得到你描述的结果,你可以使用这个:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="one:*" xmlns:one="http://x.com/xsd/so" >
<xsl:element name="name()" namespace="namespace-uri()">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
或者您可以使用更通用、与命名空间无关的方法:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="name()" namespace="namespace-uri()">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
这两者都会产生你所说的你想要的输出。
【讨论】:
【参考方案2】:你想要的xsl:copy-of
表达式就是这个,只复制与当前元素匹配的命名空间
<xsl:copy-of select="namespace::*[. = namespace-uri(..)]"/>
此外,您应该使用name()
而不是local-name()
创建元素,否则您将在没有命名空间中创建元素,因为您没有默认命名空间。
但是,由于您正在创建一个带有已在 XSLT 中声明的前缀的新元素,我认为您根本不需要复制名称空间。
试试这个 XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:one="http://x.com/xsd/so">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="one:*">
<xsl:element name="name()">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
注意,如果您可以使用 XSLT 2.0,您也可以这样做......
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:one="http://x.com/xsd/so">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="one:*">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
【讨论】:
事实上,您可以在顶层无条件地执行<xsl:copy-of select="/" copy-namespaces="no"/>
- 这会删除所有未使用的命名空间,这些命名空间可能(或可能不)满足要求。无论如何,它适用于这个例子。以上是关于如何从 XML 元素中删除一个特定的命名空间的主要内容,如果未能解决你的问题,请参考以下文章