0
votes

Here is my XML:

<Tree All="False">
  <Menu Type="Leaf">
    <Label>Menu 1</Label>
  </Menu>
  <Menu>
    <Label>Menu 2</Label>
  </Menu>
  <Menu>
    <Label>Menu 3</Label>
  </Menu>
  <Break />
  <Menu>
    <Label>Menu 4</Label>
  </Menu>
  <Menu>
    <Label>Menu 5</Label>
  </Menu>
  <Menu>
    <Label>Menu 6</Label>
  </Menu>
  <Menu>
    <Label>Menu 7</Label>
  </Menu>
  <Break />
  <Menu>
    <Label>Menu 8</Label>
  </Menu>
</Tree>

I'm trying to convert the nodes into an HTML table, with <Break /> node as the separator. The expected HTML output is:

enter image description here

I'm able to group the nodes by Muenchian method using XSLT 1.0. But now I'm stuck at converting them to HTML table. Here is my current XSLT:

<xsl:key name="groups" match="Tree*[not(self::Break)]" use="count(preceding-sibling::Break)" />

<xsl:template match="Tree">
  <xsl:variable name="groupings" select="*[not(self::Break)][generate-id() = generate-id(key('groups', count(preceding-sibling::Break))[1])]" />
  <xsl:for-each select="$groupings">
    <xsl:sort select="count(key('groups', count(preceding-sibling::Break)))" order="descending" />
    <xsl:if test="position() = 1">
      <xsl:variable name="rows" select="count(key('groups', count(preceding-sibling::Break)))" />
      <xsl:call-template name="GroupTemplate">
        <xsl:with-param name="rows" select="$rows" />
        <xsl:with-param name="groupings" select="$groupings" />
      </xsl:call-template>
    </xsl:if>
  </xsl:for-each>
</xsl:template>

<xsl:template name="GroupTemplate">
  <xsl:param name="rows" />
  <xsl:param name="groupings" />
  <table>
    <xsl:for-each select="$groupings">
      <xsl:variable name="group" select="key('groups', count(preceding-sibling::Break))" />
      <xsl:for-each select="$group[position() &lt;= $rows]">
        <xsl:value-of select="." />
      </xsl:for-each>
      <br></br>
    </xsl:for-each>
  </table>
</xsl:template>

My current code is giving me this result, which is incorrect:

Menu 1 Menu 2 Menu 3

Menu 4 Menu 5 Menu 6 Menu 7

Menu 8

1

1 Answers

2
votes

You've started off correctly, by identifying the group with the maximum number of rows. What you really need to do is an "for 1 to $maxorw" in your template, which you can do in XSLT 2.0, but not 1.0 easily. What you could do though is that instead of passing in the value of the max rows, pass in the group with the max rows instead, and select from that to start with. The 'position' then gives you the "1 to 4" you need.

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="5.0" />
<xsl:key name="groups" match="Tree/*[not(self::Break)]" use="count(preceding-sibling::Break)" />

<xsl:template match="Tree">
  <xsl:variable name="groupings" select="*[not(self::Break)][generate-id() = generate-id(key('groups', count(preceding-sibling::Break))[1])]" />
  <xsl:for-each select="$groupings">
    <xsl:sort select="count(key('groups', count(preceding-sibling::Break)))" order="descending" />
    <xsl:if test="position() = 1">
      <xsl:variable name="maxRows" select="key('groups', count(preceding-sibling::Break))" />
      <xsl:call-template name="GroupTemplate">
        <xsl:with-param name="maxRows" select="$maxRows" />
        <xsl:with-param name="groupings" select="$groupings" />
      </xsl:call-template>
    </xsl:if>
  </xsl:for-each>
</xsl:template>

<xsl:template name="GroupTemplate">
  <xsl:param name="maxRows" />
  <xsl:param name="groupings" />
  <table>
    <xsl:for-each select="$maxRows">
      <xsl:variable name="position" select="position()" />
      <tr>
        <xsl:for-each select="$groupings">
          <xsl:variable name="group" select="key('groups', count(preceding-sibling::Break))" />
          <td>
            <xsl:value-of select="normalize-space($group[position() = $position])" />
          </td>
        </xsl:for-each>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>
</xsl:stylesheet>