Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

summing nodes' values grouping by pattern of other nodes' values

The set-up

I have an XML file with (this is simplified from actual):

<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>

Each week has many entrys; each entry has just two data elements, one with name="foo" and the other with name="path", and a single numeric element with name="bar" and value an integer. There can be partial-duplicate entrys, even within a week: entrys can have the same foo or the same path, but no two entrys within a week that have the same foo and the same path.

What I want

I'd like to separate my paths into categories. For example, I want all paths matching the regex /ISOcodes/ to be considered separately (as "ISOcodes", say) and all paths matching ^/news as a separate category ("news").

I'm trying to sum the value of bar across multiple entrys within a single week, grouping by foo and by type (as in previous paragraph) of path. That is, for each week, for each value of foo, for each category of path (as in the preceding paragraph), I want the sum() of the values of bar.

Is there a way to do this? How?

like image 342
msh210 Avatar asked Nov 25 '25 14:11

msh210


1 Answers

An XSLT 2.0 solution:

<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>

On the following input:

<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>

Produces:

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

Obviously, you'll need to format additional elements to taste, but this should demonstrate the grouping method.

like image 155
Wayne Avatar answered Nov 27 '25 05:11

Wayne



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!