Группировка похожих элементов в отдельные группы - PullRequest
0 голосов
/ 29 февраля 2020

У меня есть следующее XML:

<root>
  <node>
    <prop>a</prop>
    <amount>10</amount>
  </node>
  <node>
    <prop>a</prop>
    <amount>20</amount>
  </node>
  <node>
    <prop>b</prop>
    <amount>15</amount>
  </node>
  <node>
    <prop>b</prop>
    <amount>25</amount>
  </node>
  <node>
    <prop>a</prop>
    <amount>17</amount>
  </node>
</root>

Я хочу сгруппировать узлы в сегменты в соответствии с их prop:

<root>
  <segment>
    <prop>a</prop>
    <node>
      <amount>10</amount>
    </node>
    <node>
      <amount>20</amount>
    </node>
  </segment>
  <segment>
    <prop>b</prop>
    <node>
      <amount>15</amount>
    </node>
    <node>
      <amount>25</amount>
    </node>
  </segment>
  <segment>
    <prop>a</prop>
    <node>
      <amount>17</amount>
    </node>
  </segment>
</root>

, но, как вы можете видеть последний «а» узел должен быть помещен в другой segment - это потому, что три «а» узла не являются смежными. Когда я пытаюсь сгруппировать их, все «а» узлы объединяются. Есть ли способ сгруппировать их, как указано в примере?

1 Ответ

1 голос
/ 29 февраля 2020

Попробуйте это в XSLT 1.0

    <?xml version="1.0" encoding="UTF-8"?>
<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:output indent="yes"/>

    <xsl:template match="root">
        <xsl:copy>
            <xsl:for-each select="node[position() = 1 or prop != preceding-sibling::node[1]/prop]">
                <segment>
                    <xsl:copy-of select="prop"/>
                    <xsl:variable name="prop" select="prop"/>
                    <xsl:call-template name="retrivenode">
                        <xsl:with-param name="currentnode" select="."/>
                        <xsl:with-param name="prop" select="$prop"/>
                    </xsl:call-template>
                </segment>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="retrivenode">
        <xsl:param name="currentnode"/>
        <xsl:param name="prop"/>
        <xsl:apply-templates select="$currentnode"/>
        <xsl:if test="$currentnode/following-sibling::node[1][prop = $prop]">
            <xsl:call-template name="retrivenode">
                <xsl:with-param name="currentnode" select="$currentnode/following-sibling::node[1]"/>
                <xsl:with-param name="prop" select="$prop"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="node">
        <xsl:copy>
            <xsl:apply-templates select="*[not(local-name() = 'prop')]">

            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

См. Преобразование в https://xsltfiddle.liberty-development.net/3NSTbfk

...