如何从XML元素中删除一个特定的名称空间

时间:2018-06-22 10:48:51

标签: xml xslt namespaces

我一直在寻找这种特殊情况,但没有找到。我有这个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>

2 个答案:

答案 0 :(得分:1)

您想要的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>

答案 1 :(得分:1)

有很多因素阻止了它创建您描述的结果:

在这里,您只复制元素使用的名称空间,而不是它所使用的名称空间:

<xsl:copy-of select="namespace::*[not(. = namespace-uri(..))]"/>

这里您要在null命名空间(没有命名空间)中创建一个元素:

<xsl:element name="{local-name()}">

您已经在XSLT样式表的根元素上声明了onetwo命名空间,这意味着它们将包含在输出文档的根元素中。

为了获得您描述的结果,可以使用以下方法:

<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>

这两种方法都能产生您想要的输出。