开发者

XSLT split repeat elements into separate groups while maintaining siblings

I am trying to split groups of elements into groups that contain a unique set of elements while maintaining all sibling relationships in the split. For instance, I’d like the following xml:

<group>
    <b074>11</b074>
    <b075>03</b075>
    <b076>9</b076>
    <b075>04</b075>
    <b076>12</b076>
</group>
<group>
    <b074>11</b074>
    <b075>04</b075>
    <b076>4</b076>
</group>

To be transformed to:

<group>
    <b074>11</b074>
    <b075>03</b075>
    <b076>9</b076>
</group>
<group>
    <b074>11</b074>
    <b075>04</b075>
    <b076>12</b076>
</group>
<group>
    <b074>11</b074>
    <b075>04</b075>
    <b076>4</b076>
</group>

EDIT: The first group in the initial data has duplicate elements. For example the element <b075> occurs twice. I would like for the second occ开发者_C百科urrence of <b075> to be in a new group in the result. That's what I meant by unique set.

EDIT #2: Forgot to mention that when the second <b075> is pulled out into its own group, its sibling <b074> is "copied" along. That's what i meant by keeping the siblings.

EDIT #3: (I apologize, I should have explained this more thoroughly the first time) The way you know that <b074> belongs in the resulting group is because it occurs once. All elements in the original group that occur once are shared by all the resulting groups. The repeating elements are also going to be listed sequentially, meaning if elements <b075> and <b076> repeat, they will be next to each other, <b075>, then immediately <b076>. So the number of resulting groups, is the number of such repeating chunks of elements (2 in the case of this example).

Unfortunately, I am new to XSLT, but I have attempted unsuccessfully to apply variations of the solutions found at XSLT split a tree at a descendent node and Move separator elements upwards in xml hierarchy, as they seem very close to what I am trying to accomplish.

I am using 1.0 – 2.0 is not an option for me. Any help would be appreciated.


If i understand your conditions right, following transformation is what you want:

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

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="group">
        <xsl:apply-templates select="*[1]" mode="group"/>
    </xsl:template>

    <xsl:template match="*" mode="group">
        <xsl:param name="level" select="0"/>
        <xsl:variable name="name" select="name()"/>
        <xsl:variable name="needs-group" select="count( preceding-sibling::*[ name() = $name ] ) = $level"/>
        <xsl:if test="$needs-group">
            <group>
                <xsl:apply-templates select="preceding-sibling::*[ name() != $name ]" mode="item-group">
                    <xsl:with-param name="level" select="$level"/>
                </xsl:apply-templates>

                <xsl:apply-templates select="."/>

                <xsl:apply-templates select="following-sibling::*[ name() != $name ]" mode="item-group">
                    <xsl:with-param name="level" select="$level"/>
                </xsl:apply-templates>
            </group>
        </xsl:if>

        <xsl:apply-templates select="following-sibling::*[1]" mode="group">
            <xsl:with-param name="level" select="$level + $needs-group"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*" mode="item-group">
        <xsl:param name="level"/>
        <xsl:variable name="name" select="name()"/>
        <xsl:if test="( count( preceding-sibling::*[ name() = $name ] ) = $level ) or ( count( ../*[ name() = $name ] ) &lt;= $level and not( following-sibling::*[ name() = $name ] ) )">
            <xsl:apply-templates select="."/>
        </xsl:if>
    </xsl:template>

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

</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜