Q:

XSL: Placing multiple entries in one html tag without breaking the tag structure

My XML source looks as follows:
<query>
  <Rows>
    <Row ID="1" name="person1" title="p1package1" />
    <Row ID="2" name="person1" title="p1package2" />
    <Row ID="3" name="person2" title="p2package1" />
  </Rows>
</query>

And I want to create an output with XSL like this:
<table>
  <tr>
    <td>person1</td>
    <td>p1package1, p1package2</td>
  </tr>
  <tr>
    <td>person2</td>
    <td>p2package1</td>
  </tr>
</table>

I tried it with the following XSL-sylesheet, but the open  before the first  seems to cause an invalid structure so the page cannot load.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output version="1.0" indent="yes" encoding="UTF-8" method="xml" />  
    <xsl:template match='query'>
      <table>
        <xsl:for-each select="Rows/Row" >
          <xsl:if test="preceding-sibling::Row/@name != @name or position() = 1">
              <tr>
                <td><xsl:value-of select="@name" /></td>
                <td>
          </xsl:if>
          <xsl:value-of select="@title" />
          <xsl:if test="not(following-sibling::Row/@name = @name)">
                </td>
              </tr>
          </xsl:if>
        </xsl:for-each>
      </table>
    </xsl:template>
</xsl:stylesheet>

How could I approach this? I know the XML is not structured nicely but I have no influence on the data source.

A:

The standard approach to grouping problems like this in XSLT 1.0 is Muenchian grouping - you define a key that groups your items in the way you want and then use a generate-id() trick to process just the first item with each key value.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output version="1.0" indent="yes" encoding="UTF-8" method="xml" />

  <xsl:key name="rowByName" match="Row" use="@name" />

  <xsl:template match="/">
    <table>
      <!-- apply templates for the first Row with each name -->
      <xsl:apply-templates select="query/Rows/Row[generate-id() =
          generate-id(key('rowByName', @name)[1])]" />
    </table>
  </xsl:template>

  <xsl:template match="Row">
    <tr>
      <td><xsl:value-of select="@name" /></td>
      <td>
        <!-- concatenate the title attributes of all rows with this name -->
        <xsl:for-each select="key('rowByName', @name)">
          <xsl:if test="position() &gt; 1">, </xsl:if>
          <xsl:value-of select="@title" />
        </xsl:for-each>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

