从一些xml中删除所有节点

时间:2017-05-23 17:36:35

标签: xml xslt

我有一个像这样的简单xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <garbage1>something</garbage1>
    <garbage2>something</garbage2>
    <garbage3>something</garbage3>
    <item>
        <a>
            <b/>
            <c>123</c>
        </a>
        <d>456</d>
    </item>
    <item>
        <a>
            <b/>
            <c>789</c>
        </a>
        <d>666</d>
    </item>
</root>

我想删除<c>节点中除<d><item>之外的所有节点,以获得如下结果:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <item>
        <c>123</c>
        <d>456</d>
    </item>
    <item>
        <c>789</c>
        <d>666</d>
    </item>
</root>

显然,正确的做法是使用身份转换然后相应地覆盖它。如果我只想删除<c><d>,则可以执行此操作:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!--    identity transformation-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--    override identity transformation-->
    <xsl:template match="c|d"/>

</xsl:stylesheet>

好的,所以我只需要否定参数来摆脱所有非<c><d>的节点。为什么这不起作用?

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!--    identity transformation-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--    override identity transformation to (apparently not) get rid of all nodes except 'c' and 'd'-->
    <xsl:template match="//*[not(local-name() = ('c', 'd'))]"/>

</xsl:stylesheet>

非常感谢你,我想在这里错过一些简单的东西......

2 个答案:

答案 0 :(得分:1)

首先,实现目标的正确方法:

  

删除<c>个节点中除<d><item>以外的所有节点

是:

XSLT 1.0 / 2.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[ancestor::item][not(self::c or self::d)]">
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>

这匹配“<item>”内的任何节点(即item的后代),cd除外,并将模板应用于其子节点,复制它本身。因此,例如,a包装器已被删除 - 但其c子项仍由标识转换模板处理。

您的尝试无效,因为您的第二个模板已应用于root元素。从那里,模板没有输出任何东西,也没有应用任何其他模板 - 所以处理在那一点结束,结果为空。

答案 1 :(得分:0)

我找到了一种方法来解决这个问题:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="@*|node()">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:template>

    <xsl:template match="root">
        <root>
            <xsl:apply-templates select="@*|node()"/>
        </root>
    </xsl:template>

    <xsl:template match="item">
        <item>
            <xsl:apply-templates select="@*|node()"/>
        </item>
    </xsl:template>

    <xsl:template match="c | d">
        <xsl:copy-of select="."/>
    </xsl:template>


</xsl:stylesheet>

然而,这仍然让我觉得我最初的想法有什么不妥,所以如果有人可以帮助我,我会很高兴。