Создание агрегатного узла через XSLT с кикером - PullRequest
0 голосов
/ 28 сентября 2011

Я не очень хорошо думаю в xsl, поэтому мне сложно понять, как справиться с этим. Мне нужно сделать агрегат количества, но сгруппированы по идентификатору в атрибуте в родительском узле. Я думаю, что это должен быть ужасно простой шаблон рекурсии, но у меня возникают проблемы с его накачкой

Этот входной XML выглядит так:

<foo>
  <lines>
    <line line_id="10000">
      <qty>10</qty>
    </line>
    <line line_id="10000">
      <qty>4</qty>
    </line>
    <line line_id="10000">
      <qty>12</qty>
    </line>
    <line line_id="20000">
      <qty>1</qty>
    </line>
    <line line_id="30000">
      <qty>4</qty>
    </line>
    <line line_id="30000">
      <qty>6</qty>
    </line>
  </lines>
  <lines>
    <line line_id="10000">
      <qty>4</qty>
    </line>
  </lines>
</foo>

Вывод должен быть:

<newfoo>
  <items>
    <item>
      <item_id>10000</item_id>
      <quantity>26</quantity>
    </item>
    <item>
      <item_id>20000</item_id>
      <quantity>1</quantity>
    </item>
    <item>
      <item_id>30000</item_id>
      <quantity>10</quantity>
    </item>
  </items>
  <items>
    <item>
      <item_id>10000</item_id>
      <quantity>4</quantity>
    </item>
  </items>
</newfoo>

1 Ответ

0 голосов
/ 28 сентября 2011

Это может быть достигнуто в XSLT1.0 с помощью метода, называемого группировкой Muenchian.

Сначала вы определяете ключ для поиска элементов line для данного элемента lines , используя атрибут line_id в качестве ключа. Таким образом, для данного элемента lines и атрибута line_id будут возвращены все соответствующие элементы line . Для этого вам понадобится сцепленный ключ.

<xsl:key name="id" 
   match="line" 
   use="concat(concat(generate-id(..), ','), @line_id)"/>

Далее необходимо сопоставить элементы line , которые имеют первое вхождение каждого отдельного атрибута line_id в элементе lines . Это достигается следующим образом:

<xsl:apply-templates 
  select="line[
    generate-id() = 
    generate-id(key('id',concat(concat(generate-id(..),','),@line_id))[1])]" />

т.е. Совпадение line элементов, которые являются первыми элементами в списке для данного ключа.

Затем вы можете получить общее количество, просто суммируя все элементы в ключе

<xsl:value-of 
  select="sum(key('id', concat(concat(generate-id(..), ','), @line_id))/qty)"/>

Вот полный документ XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:key name="id" match="line" use="concat(concat(generate-id(..), ','), @line_id)"/>

   <xsl:template match="/foo">
      <newfoo>
         <xsl:apply-templates select="lines"/>
      </newfoo>
   </xsl:template>

   <xsl:template match="lines">
      <items>
         <xsl:apply-templates select="line[generate-id() = generate-id(key('id', concat(concat(generate-id(..), ','), @line_id))[1])]"/>
      </items>
   </xsl:template>

   <xsl:template match="line">
      <item>
         <item_id>
            <xsl:value-of select="@line_id"/>
         </item_id>
         <quantity>
            <xsl:value-of select="sum(key('id', concat(concat(generate-id(..), ','), @line_id))/qty)"/>
         </quantity>
      </item>
   </xsl:template>
</xsl:stylesheet>

Применительно к следующему XML:

<foo>
   <lines>
      <line line_id="10000">
         <qty>10</qty>
      </line>
      <line line_id="10000">
         <qty>4</qty>
      </line>
      <line line_id="10000">
         <qty>12</qty>
      </line>
      <line line_id="20000">
         <qty>1</qty>
      </line>
      <line line_id="30000">
         <qty>4</qty>
      </line>
      <line line_id="30000">
         <qty>6</qty>
      </line>
   </lines>
   <lines>
      <line line_id="10000">
         <qty>4</qty>
      </line>
   </lines>
</foo>

Выводится следующий XML:

<newfoo>
   <items>
      <item>
         <item_id>10000</item_id>
         <quantity>26</quantity>
      </item>
      <item>
         <item_id>20000</item_id>
         <quantity>1</quantity>
      </item>
      <item>
         <item_id>30000</item_id>
         <quantity>10</quantity>
      </item>
   </items>
   <items>
      <item>
         <item_id>10000</item_id>
         <quantity>4</quantity>
      </item>
   </items>
</newfoo>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...