Hash
Hash

Reputation: 8020

XSLT add attribute value based on another value

How can i add values based on another value?

<?xml version="1.0" encoding="UTF-8"?>
<items>
   <item id="A1" quantity="5">
      <info type="ram x1" import="CA" />
   </item>
   <item id="A2" quantity="3">
      <info type="ram x1" import="SA" />
   </item>
   <item id="A3" quantity="10">
      <info type="ram x2" import="AU" />
   </item>
</items>

I need to add all quantities based on the type for example i need an output as,

ram x1 quantity=8 ram x2 quantity=10

<?xml version="1.0" encoding="UTF-8"?>
<items>
        <details type="ram x1" quantity="8"/>
        <details type="ram x2" quantity="10"/>
</items>

tried for-each-group to get quantity first to see if it works,

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="html" indent="yes" />
   <xsl:template match="items">
      <xsl:for-each-group select="item" group-by="info/@type">
         <xsl:value-of select="sum(@quantity)" />
      </xsl:for-each-group>
   </xsl:template>
</xsl:stylesheet>

Upvotes: 2

Views: 660

Answers (2)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22617

@Kirill Polishchuck has given a good answer already, I would like to add a full stylesheet to illustrate this.

It outputs XML formatted in the way you have shown it should be. Apart from making use of current-group(), there is also an interesting application of current-grouping-key() which retrieves the value that caused the current items to be grouped together.

You have specified xsl:output method to be HTML, but your expected output looks like XML. Therefore, I have altered it to output XML.

Stylesheet

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

 <xsl:output method="xml" indent="yes" />

 <xsl:template match="items">
  <xsl:copy>
     <xsl:for-each-group select="item" group-by="info/@type">
        <details>
           <xsl:attribute name="type">
              <xsl:value-of select="current-grouping-key()"/>
           </xsl:attribute>
           <xsl:attribute name="quantity">
              <xsl:value-of select="sum(current-group()/@quantity)" />
           </xsl:attribute>
        </details>
     </xsl:for-each-group>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

Output

<?xml version="1.0" encoding="UTF-8"?>
<items>
  <details type="ram x1" quantity="8"/>
  <details type="ram x2" quantity="10"/>
</items>

An even more concise (but more intricate) version uses so-called attribute value templates:

<xsl:for-each-group select="item" group-by="info/@type">
   <details type="{current-grouping-key()}" quantity="{sum(current-group()/@quantity)}"/>
</xsl:for-each-group>

Upvotes: 0

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56162

Use current-group() function, i.e.:

<xsl:value-of select="sum(current-group()/@quantity)" />

Upvotes: 3

Related Questions