XSLT 1.0 Группировка по / отличному значению узлов xml

У меня есть файл XML, который содержит список узлов MOVIMENTO, и мне нужно сгруппировать эти узлы по значению под-тега SIGLA с XSLT 1.0.

<RESULT>

   <MOVIMENTO> <!-- MOVIMENTO: nodes to cicle into -->
      <INFO>
         <MOV_AREA>10</MOV_AREA>
      </INFO>
      <ARTICOLI>
         <ARTICOLO>
             <SIGLA>80069</SIGLA> <!-- SIGLA: nodes to group by distinct value -->
             <UM>NR</UM>
             <QTA_CONS>1,00</QTA_CONS>
         </ARTICOLO>
      </ARTICOLI>
   </MOVIMENTO>

   <MOVIMENTO>
      <INFO>
         <MOV_AREA>13</MOV_AREA>
      </INFO>
      <ARTICOLI>
         <ARTICOLO>
             <SIGLA>80069</SIGLA>
             <UM>NR</UM>
             <QTA_CONS>1,00</QTA_CONS>
         </ARTICOLO>
      </ARTICOLI>
   </MOVIMENTO>

   <MOVIMENTO>
      <INFO>
         <MOV_AREA>14</MOV_AREA>
      </INFO>
      <ARTICOLI>
         <ARTICOLO>
             <SIGLA>77586</SIGLA>
             <UM>NR</UM>
             <QTA_CONS>1,00</QTA_CONS>
         </ARTICOLO>
      </ARTICOLI>
   </MOVIMENTO>

</RESULT>

Я пробовал много решений, основанных на примерах, найденных в сети, но у меня ничего не работает правильно. Кто-то может мне помочь? Ниже код, который я использую:

   <?xml version="1.0" encoding="utf-8"?>
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

      <xsl:key name="groups" match="ARTICOLO" use="SIGLA" />

      <xsl:template match="RESULT">
         <xsl:apply-templates select="MOVIMENTO/ARTICOLI/ARTICOLO[generate-id() = generate-id(key('groups', SIGLA)[1])]"/>
      </xsl:template>

      <xsl:template match="ARTICOLO">
          <xsl:for-each select="key('groups', SIGLA)">
             SIGLA: <xsl:value-of select="normalize-space(SIGLA)"/>
          </xsl:for-each>
      </xsl:template>

   </xsl:stylesheet>

1 ответ

Решение

В коде XSLT требуется некоторая настройка. Ключ должен быть изменен на

<xsl:key name="groups" match="MOVIMENTO" use="ARTICOLI/ARTICOLO/SIGLA" />

Вы можете использовать identity transform шаблон для копирования элементов как есть, а затем применить группировку.

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

Подходим <MOVIMENTO> шаблоны для сгруппированных элементов, а затем цикл по ключу для отдельных элементов.

<xsl:template match="MOVIMENTO[generate-id() = generate-id(key('groups', ARTICOLI/ARTICOLO/SIGLA)[1])]">
    <xsl:copy>
        <xsl:for-each select="key('groups', ARTICOLI/ARTICOLO/SIGLA)">
            <xsl:apply-templates select="INFO" />
        </xsl:for-each>
        <xsl:apply-templates select="key('groups', ARTICOLI/ARTICOLO/SIGLA)[1]/ARTICOLI" />
    </xsl:copy>
</xsl:template>

Наконец, для любого другого <MOVIMENTO> узлы, ничего не делать.

<xsl:template match="MOVIMENTO" />

Выход как ниже

<RESULT>
    <MOVIMENTO>
        <INFO>
            <MOV_AREA>10</MOV_AREA>
        </INFO>
        <INFO>
            <MOV_AREA>13</MOV_AREA>
        </INFO>
        <ARTICOLI>
            <ARTICOLO>
                <SIGLA>80069</SIGLA>
                <UM>NR</UM>
                <QTA_CONS>1,00</QTA_CONS>
            </ARTICOLO>
        </ARTICOLI>
    </MOVIMENTO>
    <MOVIMENTO>
        <INFO>
            <MOV_AREA>14</MOV_AREA>
        </INFO>
        <ARTICOLI>
            <ARTICOLO>
                <SIGLA>77586</SIGLA>
                <UM>NR</UM>
                <QTA_CONS>1,00</QTA_CONS>
            </ARTICOLO>
        </ARTICOLI>
    </MOVIMENTO>
</RESULT>
Другие вопросы по тегам