0

After a first xsl transformation I have a xml output similar to the following one:

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

But now I need to obtain a second output where file nodes are merged if they have the same path attribute as follows:

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

I don't know possible @pathvalues in advance.

I looked at multiple posts about nodes merging but could not find a way to do what I want. I'm lost with nodes grouping, keys, id generation... and only obtained error messages so far.

Could you please help me to get the 2nd output starting from the first one (with xls 1.0) ? And if you could provide some references (websites) where I could find explanations about such kind of transformations it would be really great.

Note : the @nb attribute of two line nodes of two file nodes having the same @path never collide, it is unique, i.e. this will never happen :

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

Thank you a lot for your help !

4

1 回答 1

2

没有键的 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 带有用于 Mü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>

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

于 2015-09-22T22:03:38.390 回答