goshanoob
goshanoob

Reputation: 75

XSLT-2.0: grouping by node content

We need to do a grouping table rows on the content of the first column, and then perform a certain amount of processing for each row in the group. The contents of the first column - numbers. It would be approached for-each-group, if the columns do not contain any number of digits.

Example input:

<table>
  <tr><td>1</td></tr>
  <tr><td>2</td></tr>
  <tr><td>1</td></tr>
  <tr><td>1,2,3</td></tr>
  <tr><td>1,4</td></tr>
</table>

According to the task, I should have 4 groups:

The general template looks like this:

<xsl:template match="table">
  <xsl:for-each-group select="tr" group-by="td[1]"> 
   <xsl:for-each select="current-group()">  
    <!-- transformation -->
   </xsl:for-each>
  </xsl:for-each-group>
</xsl:template>

So that group-by = "td [1]" doesn't work.
The key with regular expressions... I find it difficult.

Upvotes: 1

Views: 263

Answers (3)

Rolf Rander
Rolf Rander

Reputation: 3321

If you want to output the original row-numbers containing the values of each group, I think you need to transform the input into another datastructure which includes the original position(). Something like this:

<xsl:template match="table">
    <xsl:variable name="row-data">
        <xsl:for-each select="tr/td">
            <xsl:variable name="row" select="position()" />
            <xsl:for-each select="tokenize(., ',')">
                <data>
                <xsl:attribute name="row" select="$row" />
                <xsl:attribute name="value" select="." />
                </data>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:variable>

    <data>
      <xsl:for-each-group select="$row-data/*" group-by="@value"> 
       <group>
            <xsl:attribute name="value" select="@value" />
            <xsl:value-of select="current-group()/@row" separator=","/>
       </group>
      </xsl:for-each-group>
    </data>
</xsl:template>

Upvotes: 0

C. M. Sperberg-McQueen
C. M. Sperberg-McQueen

Reputation: 25054

I think you are saying that

  1. As input you have a table with rows and columns.
  2. The first column of each row contains a comma-separated list of numbers. Rows may contain additional columns, though these are not shown in your example.
  3. As output you'd like one group for each distinct numeric value in the set of comma-delimited lists of numbers, consisting of the rows which include that numeric value in the comma-separated list in their first column.

It follows from the last point that a row will appear either once for each numeral in the comma-delimited list in its first column, or once for each distinct value in that list (spec not clear).

I'd try

<xsl:for-each-group select="tr"
  group-by="tokenize(td[1],',')">
  <xsl:message>Now processing <xsl:value-of 
      select="count(current-group()"/>rows containing <xsl:value-of 
      select="current-grouping-key()"/> in column 1.</
  ...
</

(Not tested.)

Upvotes: 0

Martin Honnen
Martin Honnen

Reputation: 167716

It sounds as if you want to replace <xsl:for-each-group select="tr" group-by="td[1]"> by <xsl:for-each-group select="tr" group-by="tokenize(td[1], ',')">.

Upvotes: 2

Related Questions