如何根据属性的值合并节点



在第一次xsl转换之后,我有一个类似于以下的xml输出:

<?xml version="1.0" encoding="UTF-8"?>
<analysis type="1">
    <file path="a.txt">
        <line nb="23" found="true"/>
        <line nb="36" found="true" count="2"/>
        <line nb="98" found="true"/>
    </file>
    <file path="a.txt">
        <line nb="100" found="false"/>
    </file>
    <file path="b.txt">
        <line nb="10" found="false"/>
    </file>
    <!-- more file nodes below with different @path -->
</analysis>

但现在我需要获得第二个输出,其中file节点合并,如果它们具有相同的path属性,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<analysis type="1">
    <file path="a.txt">
        <line nb="23" found="true"/>
        <line nb="36" found="true" count="2"/>
        <line nb="98" found="true"/>
        <line nb="100" found="false"/>
    </file>
    <file path="b.txt">
        <line nb="10" found="false"/>
    </file>
</analysis>

我不知道可能的@path值。

我看了很多关于节点合并的帖子,但找不到一种方法来做我想要的。我失去了节点分组,密钥,id生成…到目前为止只获得了错误消息。

你能帮我从第一个输出(xls 1.0)开始得到第二个输出吗?如果你能提供一些参考(网站),在那里我可以找到关于这种转换的解释,那就太好了。

注意:具有相同@path的两个file节点的两个line节点的@nb属性永远不会碰撞,它是唯一的,即永远不会发生这种情况:

<?xml version="1.0" encoding="UTF-8"?>
<analysis type="1">
    <file path="a.txt">
        <line nb="36" found="true" count="2"/>
    </file>
    <file path="a.txt">
        <line nb="36" found="true"/>
    </file>
</analysis>

非常感谢您的帮助

不带键的XPath 1.0

既然你在问题中说你在理解键方面有困难,这里有一种方法可以在没有键的情况下做到,使用一种称为兄弟递归的技术。它被认为不如使用键好,因为它使用兄弟轴,这通常是相当慢的。然而,在大多数实际情况下,您不会注意到差异:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="analysis">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="file[not(preceding-sibling::file/@path = @path)]" mode="sibling-recurse" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="file" mode="sibling-recurse">
        <xsl:copy>
            <!-- back to default mode -->
            <xsl:apply-templates select="node() | @*" />
            <xsl:apply-templates select="following-sibling::file[current()/@path = @path]" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="file">
        <xsl:apply-templates select="node()" />
    </xsl:template>
</xsl:stylesheet>

带键的XPath 1.0,用于 nchian分组

这种方法使用了m nchian分组,这在其他地方有解释(只需在手头有此代码的情况下遵循类似的教程)。它也使用兄弟轴,但以一种破坏性小得多的方式(即,不需要在每个单个节点测试中遍历整个兄弟轴)。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:key match="file" use="@path" name="path" />
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="analysis">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="file[generate-id(.) = generate-id(key('path', @path))]" mode="sibling-recurse" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="file" mode="sibling-recurse">
        <xsl:copy>
            <!-- back to default mode -->
            <xsl:apply-templates select="node() | @*" />
            <xsl:apply-templates select="following-sibling::file[@path = current()/@path]/node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

注意:对于这两种方法,模式切换都不是完全必要的,但它使编写简单的匹配模式更容易,并防止优先级冲突或难以发现的bug (imo)。

相关内容

  • 没有找到相关文章

最新更新