【问题标题】:XSLT split repeat elements into separate groups while maintaining siblingsXSLT 将重复元素拆分为单独的组,同时保留同级元素
【发布时间】:2011-08-19 21:51:50
【问题描述】:

我正在尝试将元素组拆分为包含一组独特元素的组,同时保持拆分中的所有兄弟关系。例如,我想要以下 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>

要转化为:

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

编辑:初始数据中的第一组具有重复的元素。例如元素&lt;b075&gt; 出现两次。我希望 &lt;b075&gt; 第二次出现在结果中的一个新组中。这就是我所说的唯一集的意思。

编辑#2:忘了提到当第二个&lt;b075&gt; 被拉到它自己的组中时,它的兄弟&lt;b074&gt; 被“复制”了。这就是我说的保留兄弟姐妹的意思。

编辑#3:(抱歉,我第一次应该更彻底地解释这一点)您知道&lt;b074&gt; 属于结果组的方式是因为它发生了一次。原始组中出现一次的所有元素都由所有结果组共享。重复的元素也将按顺序列出,这意味着如果元素 &lt;b075&gt;&lt;b076&gt; 重复,它们将彼此相邻,&lt;b075&gt;,然后立即为 &lt;b076&gt;。所以结果组的数量,就是这样重复的元素块的数量(在这个例子中是 2 个)。

不幸的是,我是 XSLT 的新手,但我尝试应用在 XSLT split a tree at a descendent nodeMove separator elements upwards in xml hierarchy 找到的解决方案的变体没有成功,因为它们似乎非常接近我想要实现的目标。

我正在使用 1.0 – 2.0 不适合我。任何帮助将不胜感激。

【问题讨论】:

  • 这真的很难说清楚;例如,你怎么知道 &lt;b075&gt;04&lt;/b075&gt;&lt;b076&gt;12&lt;/b076&gt; 应该在输出中的同一组中?
  • 我看不出你所谓的“分组”背后的任何逻辑。请编辑您的问题并更好地解释。
  • @Dimitre:已编辑进一步解释。

标签: xml xslt


【解决方案1】:

如果我理解你的条件正确,下面的转换就是你想要的:

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

【讨论】:

  • 太棒了,这似乎适用于我拥有的所有测试用例。感谢您在我最终澄清问题之前提出它。不幸的是,在他获得至少 15 分之前,似乎无法投票,我所能做的就是接受答案。
  • 感谢您的接受和好问题 :) 我认为,groupitem-group 模式中的递归可以减少,我会在有时间的时候更新答案。跨度>
  • 非常好 - 我很快就放弃了,因为它看起来太难了,部分原因是未指定的输入,部分原因是跟踪迭代和相关状态的复杂性。您能在这里概述一下指导您编码的想法吗?
猜你喜欢
  • 2014-07-22
  • 2019-08-13
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 2016-11-15
  • 1970-01-01
相关资源
最近更新 更多