как сделать агрегацию в xslt 1.0 - PullRequest
0 голосов
/ 26 августа 2011

Привет, я хочу сделать несколько агрегаций в XSLT. Например, у меня есть следующий XML-файл.

    <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<reporting:root xmlns:reporting="testing">
  <reporting:default0 reporting:type="Portfolio">
    <reporting:window reporting:Id="1" reporting:level="0" reporting:name="TEST" reporting:parentId="-1">
      <reporting:folio reporting:Id="2" reporting:criteria="0" reporting:level="1" reporting:name="topfolder1" reporting:parentId="1">
        <reporting:folio reporting:Id="37" reporting:criteria="0" reporting:level="2" reporting:name="folder2" reporting:parentId="2">
          <reporting:folio reporting:Id="38" reporting:criteria="0" reporting:level="3" reporting:name="folder3" reporting:parentId="37">
            <reporting:folio reporting:Id="196" reporting:criteria="0" reporting:level="4" reporting:name="folder4" reporting:parentId="38">
              <reporting:line reporting:Id="123456" reporting:level="5" reporting:name="element1" reporting:parentId="196" reporting:positionType="0">
                <reporting:reference>element1</reporting:reference>
                <reporting:number>625</reporting:number>
              </reporting:line>
              <reporting:line reporting:Id="223456" reporting:level="5" reporting:name="element2" reporting:parentId="196" reporting:positionType="7">
                <reporting:reference>element2</reporting:reference>
                <reporting:number>475</reporting:number>
              </reporting:line>
              <reporting:folio reporting:Id="209" reporting:criteria="0" reporting:level="5" reporting:name="delta" reporting:parentId="196">
                <reporting:line reporting:Id="223456" reporting:level="6" reporting:name="element2" reporting:parentId="209" reporting:positionType="0">
                  <reporting:reference>element2</reporting:reference>
                  <reporting:number>190</reporting:number>
                </reporting:line>
              </reporting:folio>
            </reporting:folio>
          </reporting:folio>
        </reporting:folio>
      </reporting:folio>
      <reporting:folio reporting:Id="4" reporting:criteria="0" reporting:level="1" reporting:name="topfolder2" reporting:parentId="1">
        <reporting:folio reporting:Id="39" reporting:criteria="0" reporting:level="2" reporting:name="folder24" reporting:parentId="4">
          <reporting:folio reporting:Id="40" reporting:criteria="0" reporting:level="3" reporting:name="folder34" reporting:parentId="39">
            <reporting:folio reporting:Id="296" reporting:criteria="0" reporting:level="4" reporting:name="folder44" reporting:parentId="40">
              <reporting:line reporting:Id="123456" reporting:level="5" reporting:name="element3" reporting:parentId="296" reporting:positionType="0">
                <reporting:reference>element3</reporting:reference>
                <reporting:number>65525</reporting:number>
              </reporting:line>
              <reporting:folio reporting:Id="309" reporting:criteria="0" reporting:level="5" reporting:name="delta" reporting:parentId="296">
                <reporting:line reporting:Id="2234567" reporting:level="6" reporting:name="element4" reporting:parentId="309" reporting:positionType="0">
                  <reporting:reference>element4</reporting:reference>
                  <reporting:number>490</reporting:number>
                </reporting:line>
              </reporting:folio>
            </reporting:folio>
          </reporting:folio>
        </reporting:folio>
      </reporting:folio>
    </reporting:window>
  </reporting:default0>
</reporting:root> 

тогда я хочу провести агрегацию на «уровне 2». то есть все, что находится внутри 'reports: line', должно быть возвращено, и его родительский уровень 1 и уровень 2 'report: folio' также должны быть возвращены. Также для того же элемента в любой подпапке папки level2 следует объединить в единое целое. и сумма (число) также рассчитывается.

Также нет. вложенных фолио может быть 200, прежде чем появится отчет: строковый тег.

поэтому для этого xml я хочу получить результат:

topfolder,folder2,element1,625
topfolder,folder2,element2,665
topfolder2,folder24,element3,65525
topfolder2,folder24,element4,490

Надеюсь, я все правильно объяснил. Очень ценю вашу помощь.

1 Ответ

2 голосов
/ 31 августа 2011

В этом случае сначала необходимо выполнить группировку, а затем агрегирование.Вам необходимо сгруппировать элементы по уровню фолио 1, уровню 2 фолио и имени элемента.Для этого вы обычно используете метод мюнхенской группировки.

Во-первых, вы определяете xsl: key , который можно использовать для группировки всех соответствующих элементов вместе

<xsl:key name="lines" match="reporting:line" use="
concat(
 concat(
  concat(ancestor::reporting:folio[@reporting:level='1']/@reporting:name, ','),
  concat(ancestor::reporting:folio[@reporting:level='2']/@reporting:name, ',')
 ), 
 @reporting:name
)" />

Далее необходимо выбрать первый соответствующий элемент в каждой группе.

<xsl:apply-templates select="//reporting:line
  [generate-id() = 
   generate-id(key('lines', ...concatenated key...  )[1])]" />

Затем это «простой» случай суммирования всех элементов, соответствующих ключу поиска

<xsl:value-of select="sum(key('lines', $keyName)/reporting:number)" />

Если сложить все вместе, то получится

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

   <xsl:key name="lines" match="reporting:line" use="concat(concat(concat(ancestor::reporting:folio[@reporting:level='1']/@reporting:name, ','), concat(ancestor::reporting:folio[@reporting:level='2']/@reporting:name, ',')), @reporting:name)" />

   <xsl:template match="/">
      <xsl:apply-templates select="//reporting:line[generate-id() = generate-id(key('lines', concat(concat(concat(ancestor::reporting:folio[@reporting:level='1']/@reporting:name, ','), concat(ancestor::reporting:folio[@reporting:level='2']/@reporting:name, ',')), @reporting:name))[1])]" />
   </xsl:template>

   <xsl:template match="reporting:line">
      <xsl:variable name="keyName" select="concat(concat(concat(ancestor::reporting:folio[@reporting:level='1']/@reporting:name, ','), concat(ancestor::reporting:folio[@reporting:level='2']/@reporting:name, ',')), @reporting:name)" />
      <xsl:value-of select="$keyName" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="sum(key('lines', $keyName)/reporting:number)" />
      <xsl:text>&#13;</xsl:text>
   </xsl:template>
</xsl:stylesheet>

. Применительно к вашему образцу XML результат будет следующим:

topfolder1,folder2,element1,625
topfolder1,folder2,element2,665
topfolder2,folder24,element3,65525
topfolder2,folder24,element4,490
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...