Re: [xsl] XML grouping/sorting question - displaying a matrix

Subject: Re: [xsl] XML grouping/sorting question - displaying a matrix
From: "Kevin Daniels" <KevinDaniels@xxxxxxxxxxx>
Date: Wed, 31 Mar 2004 23:38:15 -0500
Jarno,

Thanks a lot for your help.  I looked at the first example you modified and
it's pretty easy to understand and works well, though it iterates over all
the test IDs in the Y axis instead of the record IDs.  You mention using a
space separated list and recursively iterating through it - I'm not sure if
that will give rise to better performance, but I ended up concatenating the
tests for each record into the variable and changing the xsl:if to use a
contains statement.  Here is the modified version (I am using | as a
separator since the real data I'm working with may contain spaces).

  <xsl:template match="records">
    <html>
      <body>
        <table>
            <tr>
              <th>ID</th>
              <xsl:for-each select="record/test[count(. |
key('test-by-name', name)[1]) = 1]">
                <xsl:sort select="count(key('test-by-name', name))"
data-type="number" order="descending"/>
                <th>
                  <xsl:value-of select="name" />
                </th>
              </xsl:for-each>
            </tr>
            <xsl:for-each select="record">
              <xsl:variable name="current">
                <xsl:for-each select="test">
                  <xsl:value-of select="name"/>|
                </xsl:for-each>
              </xsl:variable>
              <tr>
                <th>
                  <xsl:value-of select="id"/>
                </th>
                <xsl:for-each select="../record/test[count(. |
key('test-by-name', name)[1]) = 1]">
                  <xsl:sort select="count(key('test-by-name', name))"
data-type="number" order="descending"/>
                  <td>
                    <xsl:if test='contains($current, name)'>*</xsl:if>
                  </td>
                </xsl:for-each>
              </tr>
            </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>


Again, thanks for the help - it now does exactly what I need it to do.

Kevin

----- Original Message ----- 
From: <Jarno.Elovirta@xxxxxxxxx>
To: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Tuesday, March 30, 2004 2:26 AM
Subject: RE: [xsl] XML grouping/sorting question - displaying a matrix


Hi,

> Finally, I would ultimately like to sort the columns in the
> above matrix by
> element count so that the elements which appear most are in the first
> columns, though I haven't found a way to do this:
>
> ID        X    C    B    Y
> 0001      *         *
> 0002      *              *
> 0003      *    *
> 0004      *    *

  <xsl:key name="test-by-name" match="test" use="name"/>
  <xsl:template match="records">
    <html>
      <body>
        <table>
          <thead>
            <tr>
              <th>ID</th>
              <xsl:for-each select="record/test[count(. |
key('test-by-name', name)[1]) = 1]">
                <xsl:sort select="count(key('test-by-name', name))"
data-type="number" order="descending"/>
                <th>
                  <xsl:value-of select="name" />
                </th>
              </xsl:for-each>
            </tr>
          </thead>
          <tbody>
            <xsl:for-each select="record/test">
              <xsl:variable name="current" select="name"/>
              <tr>
                <th>
                  <xsl:value-of select="@id"/>
                </th>
                <xsl:for-each select="../../record/test[count(. |
key('test-by-name', name)[1]) = 1]">
                  <xsl:sort select="count(key('test-by-name', name))"
data-type="number" order="descending"/>
                  <td>
                    <xsl:if test="name = $current">*</xsl:if>
                  </td>
                </xsl:for-each>
              </tr>
            </xsl:for-each>
          </tbody>
        </table>
      </body>
    </html>
  </xsl:template>

or, if can use ext:node-set

  <xsl:template match="records" xmlns:exsl="http://exslt.org/common";>
    <html>
      <body>
        <table>
          <xsl:variable name="columns-rtf">
            <xsl:for-each select="record/test[count(. | key('test-by-name',
name)[1]) = 1]">
              <xsl:sort select="count(key('test-by-name', name))"
data-type="number" order="descending"/>
              <xsl:copy-of select="name" />
            </xsl:for-each>
          </xsl:variable>
          <xsl:variable name="columns"
select="exsl:node-set($columns-rtf)/name"/>
          <thead>
            <tr>
              <th>ID</th>
              <xsl:for-each select="$columns">
                <th>
                  <xsl:value-of select="." />
                </th>
              </xsl:for-each>
            </tr>
          </thead>
          <tbody>
            <xsl:for-each select="record/test">
              <xsl:variable name="current" select="name"/>
              <tr>
                <th>
                  <xsl:value-of select="@id"/>
                </th>
                <xsl:for-each select="$columns">
                  <td>
                    <xsl:if test=". = $current">*</xsl:if>
                  </td>
                </xsl:for-each>
              </tr>
            </xsl:for-each>
          </tbody>
        </table>
      </body>
    </html>
  </xsl:template>

or you could create a space separated list of column names and go through
that with a recursive template.

Cheers,

Jarno

Current Thread