xsl-list
[Top] [All Lists]

[xsl] Grouping By Column Heading (by Position, not by ID or element name)

2014-04-29 09:50:45
Hi,

I regularly find myself having to transform tables in XHTML. The data is 
frequently organized by column headings. This seems like an obvious opportunity 
for grouping using Keys, and I've gotten it to work, but I'm having trouble 
understanding *why* it's working.

Please note that this is not the typical grouping example where an attribute or 
element name identifies what group something belongs to but rather an example 
in which an elements *position* relative to other elements is what defines the 
group.

Given:

<table>
        <tr>
                <td>Fruits</td>
                <td>Veggies</td>
                <td>Lactose</td>
        </tr>
        <tr>
                <td>Apples</td>
                <td>Carrots</td>
                <td>Milk</td>
        </tr>
        <tr>
                <td>Bananas</td>
                <td>Peas</td>
                <td>Cheese</td>
        </tr>
        <tr>
                <td>Plums</td>
                <td>Celery</td>
                <td>Eggs</td>
        </tr>
</table>

I want to end up with:

<foods>
  <foodGroup name="Fruits">
    <food>Apples</food>
    <food>Bananas</food>
    <food>Plums</food>
  </foodGroup>
  <foodGroup name="Veggies">
    <food>Carrots</food>
    <food>Peas</food>
    <food>Celery</food>
  </foodGroup>
  <foodGroup name="Lactose">
    <food>Milk</food>
    <food>Cheese</food>
    <food>Eggs</food>
  </foodGroup>
</foods>

I've found that the following XSLT works, but I don't understand why and I 
suspect that I am just getting lucky or that the Key element could be better 
written (optimized?).

I would be very grateful if someone with more experience at this than I could 
take a look at this XSLT and explain:

1) How is a TD element (found in the USE attribute of my Key) able to act as 
unique identifier for a TR element (it's parent)?

2) How should this be done (assuming mine is not optimal)?

Please note that I realize this does not require using keys (I don't think) but 
I like using keys because it makes sense semantically.

Here's the XSLT and thanks in advance.

<xsl:key name="food-group" match="//table/tr[position() &gt; 1]" 
use="ancestor-or-self::table/tr[position() = 1]/td" />

<xsl:template match="/table">
        <xsl:element name="foods">
                <xsl:apply-templates select="tr[position() = 1]/td"/>
        </xsl:element>
</xsl:template>

<xsl:template match="td">
        <xsl:variable name="i" select="position()" />
        <xsl:element name="foodGroup">
                <xsl:attribute name="name"><xsl:value-of select="." 
/></xsl:attribute>
                <xsl:for-each select="key('food-group', .)">
                        <xsl:element name="food">
                                <xsl:value-of select="td[position() = $i]" />
                        </xsl:element>
                </xsl:for-each>
        </xsl:element>
</xsl:template>


Ted Stresen-Reuter
--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


<Prev in Thread] Current Thread [Next in Thread>