通过其他节点的值的模式对节点的值进行求和

时间:2011-12-05 18:38:47

标签: regex xslt grouping

设置

我有一个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"和{ {1}}一个整数。即使在value内,也可能存在部分重复的entryweek s可以具有相同的entry或相同的foo,但没有两个path {1}}在一周内具有相同的entry 相同的foo

我想要什么

我想将path分为几类。例如,我希望与正则表达式path匹配的所有path分别考虑(例如“ISO代码”)和匹配/ISOcodes/作为单独类别的所有paths( “新闻”)。

我正在尝试将^/news value bar加到一个entry中的多个week中,按foo进行分组类型(如前一段所述)path。也就是说,对于week的每个valuefoo的每个pathsum()的每个类别(如前一段所述),我希望value bar的{​​{1}}个。{/ p>

有办法做到这一点吗?怎么样?

2 个答案:

答案 0 :(得分:3)

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

显然,您需要格式化其他元素,但这应该展示分组方法。

答案 1 :(得分:3)

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>

这也打印了所有的铃声和​​口哨声:)