суммирование значений узлов по шаблону значений других узлов - PullRequest
3 голосов
/ 05 декабря 2011

Настройка

У меня есть XML-файл с (это упрощено от фактического):

<feeds xmlns...>
  <feed>
    <week>
      <start-date>...</start-date>
      <end-date>...</end-date>
      <entry>
        <data name="foo" value="bar"/>
        <data name="path" value="/news/releases/2011-12-05/xyzzy"/>
        <numeric name="bar" value="463284">
      </entry>
      <entry>
        <data name="foo" value="baz"/>
        <data name="path" value="/pages/ISOcodes/en-US"/>
        <numeric name="bar" value="4332">
      </entry>
      <entry>
        <data name="foo" value="bar"/>
        <data name="path" value="/"/>
        <numeric name="bar" value="23232">
      </entry>
    </week>
    ...
  </feed>
  ...
</feeds>

Каждый week имеет много entry с; каждый entry имеет только два data элемента, один с name="foo", а другой с name="path" и один numeric элемент с name="bar" и value целым числом. Может быть частично-дубликат entry с, даже в пределах week: entry с может иметь одинаковые foo или одинаковые path, но не может быть двух entry с в течение недели, имеющих одинаковые foo и одинаковые path.

Что я хочу

Я бы хотел разделить мои path на категории. Например, я хочу, чтобы все path, соответствующие регулярному выражению /ISOcodes/, рассматривались отдельно (скажем, как "коды ISO"), а все paths, соответствующие ^/news, как отдельная категория ("новости").

Я пытаюсь суммировать value из bar по нескольким entry с в пределах одного week, группируя по foo и типу (как в предыдущем абзаце) path. То есть для каждого week, для каждого value из foo, для каждой категории path (как в предыдущем абзаце) я хочу sum() из value s bar .

Есть ли способ сделать это? Как?

Ответы [ 2 ]

3 голосов
/ 05 декабря 2011

Решение XSLT 2.0:

<xsl:template match="/">
<xsl:for-each select="//week">
  <xsl:for-each-group  select="entry" group-by="./data[@name = 'foo']/@value">
    <xsl:for-each-group select="current-group()" group-by="data[@name = 'path']/@value">
      <xsl:message>
        <xsl:choose>
          <xsl:when test="current-group()/data[@name = 'path' and matches(@value, '/ISOcodes/')]">
            Sum of ISO codes : <xsl:value-of select="sum(current-group()/numeric/@value)"/>
          </xsl:when>
          <xsl:when test="current-group()/data[@name = 'path' and matches(@value, '^/news')]">
            Sum of news : <xsl:value-of select="sum(current-group()/numeric/@value)"/>
          </xsl:when>
          <xsl:otherwise>
            Sum of other categories : <xsl:value-of select="sum(current-group()/numeric/@value)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:message>
    </xsl:for-each-group>
  </xsl:for-each-group>
</xsl:for-each>
</xsl:template>

Применительно к этому XML-файлу:

<feeds>
  <feed>
    <week>
      <start-date>...</start-date>
      <end-date>...</end-date>
      <entry>
        <data name="foo" value="bar"/>
        <data name="path" value="/news/releases/2011-12-05/xyzzy"/>
        <numeric name="bar" value="463284"/>
      </entry>
      <entry>
        <data name="foo" value="baz"/>
        <data name="path" value="/pages/ISOcodes/en-US"/>
        <numeric name="bar" value="4332"/>
      </entry>
      <entry>
        <data name="foo" value="bar"/>
        <data name="path" value="/"/>
        <numeric name="bar" value="23232"/>
      </entry>
    </week>
    ...
  </feed>
  ...
</feeds>

Вывод:

[xslt]                 Sum of news : 463284
[xslt]
[xslt]                 Sum of other categories : 23232
[xslt]
[xslt]                 Sum of ISO codes : 4332

Редактировать:

Я думал, вы хотели получить сумму?Таким образом, мой код напечатал сумму:)

<xsl:template match="/">
    <xsl:for-each select="//week">
      <xsl:for-each-group  select="entry" group-by="./data[@name = 'foo']/@value">
        <xsl:variable name="foo" select="current-grouping-key()"/>
        <xsl:for-each-group select="current-group()" group-by="data[@name = 'path']/@value">
          <xsl:message>
            <xsl:choose>
              <xsl:when test="current-group()/data[@name = 'path' and matches(@value, '/ISOcodes/')]">
                Sum of <xsl:value-of select="$foo"/>-<xsl:value-of select="current-grouping-key()"/> : <xsl:value-of select="sum(current-group()/numeric/@value)"/>
              </xsl:when>
              <xsl:when test="current-group()/data[@name = 'path' and matches(@value, '^/news')]">
                Sum of <xsl:value-of select="$foo"/>-<xsl:value-of select="current-grouping-key()"/> : <xsl:value-of select="sum(current-group()/numeric/@value)"/>
              </xsl:when>
              <xsl:otherwise>
                Sum of other categories : <xsl:value-of select="sum(current-group()/numeric/@value)"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:message>
        </xsl:for-each-group>
      </xsl:for-each-group>
    </xsl:for-each>
  </xsl:template>

Это также печатает все навороты:)

3 голосов
/ 05 декабря 2011

Решение XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="week">
        <xsl:for-each-group select="entry" 
                            group-by="concat(data[@name='foo']/@value, '-', 
                    if (matches(data[@name='path']/@value, '/ISOcodes/')) 
                        then 'ISOcodes' 
                    else if (matches(data[@name='path']/@value, '^/news')) 
                        then 'news' 
                    else 'no_category')">
            [<xsl:value-of select="current-grouping-key()"/>]
            <xsl:value-of select="sum(current-group()/numeric/@value)"/>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

На следующем входе:

<feeds>
    <feed>
        <week>
            <start-date>...</start-date>
            <end-date>...</end-date>
            <entry>
                <data name="foo" value="bar"/>
                <data name="path" value="/news/releases/2011-12-05/xyzzy"/>
                <numeric name="bar" value="463284"/>
            </entry>
            <entry>
                <data name="foo" value="baz"/>
                <data name="path" value="/pages/ISOcodes/test"/>
                <numeric name="bar" value="4332"/>
            </entry>
            <entry>
                <data name="foo" value="baz"/>
                <data name="path" value="/pages/ISOcodes/en-US"/>
                <numeric name="bar" value="4332"/>
            </entry>
            <entry>
                <data name="foo" value="baz"/>
                <data name="path" value="/pages/ISOcodes/japan"/>
                <numeric name="bar" value="4332"/>
            </entry>
            <entry>
                <data name="foo" value="bar"/>
                <data name="path" value="/"/>
                <numeric name="bar" value="23232"/>
            </entry>
        </week>
    </feed>
</feeds>

Производит:

[bar-news]
463284
[baz-ISOcodes]
12996
[bar-no_category]
23232

Очевидно, вам нужно отформатироватьдополнительные элементы по вкусу, но это следует продемонстрировать методом группировки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...