RE: [xsl] Variation on adjaceny list question

Subject: RE: [xsl] Variation on adjaceny list question
From: "Simon Shutter" <simon@xxxxxxxxxxx>
Date: Fri, 16 Mar 2007 13:58:40 -0700
Thank you Charles - very much

Simon
 
-----Original Message-----
From: cknell@xxxxxxxxxx [mailto:cknell@xxxxxxxxxx] 
Sent: March 16, 2007 1:02 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: RE: [xsl] Variation on adjaceny list question

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:strip-space elements="*" />
  <xsl:output method="xml" indent="yes" encoding="UTF-8" />

    <xsl:template match="/">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="root">
      <ul>
        <xsl:apply-templates select="row[not(ParentID)]" />
      </ul>
    </xsl:template>

    <xsl:template match="row">
      <xsl:variable name="this-id" select="ID" />
      <xsl:choose>
        <xsl:when test="count(following-sibling::row[ParentID = $this-id])
&gt; 0">
          <li><xsl:value-of select="Name"/>
            <ul>
              <xsl:apply-templates select="following-sibling::row[ParentID =
$this-id]" />
            </ul>
          </li>
        </xsl:when>
        <xsl:otherwise>
          <li><xsl:value-of select="Name"/></li>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
    
  <xsl:template match="ID" />
  <xsl:template match="Name" />
  <xsl:template match="ParentID" />
  
</xsl:stylesheet>
-- 
Charles Knell
cknell@xxxxxxxxxx - email



-----Original Message-----
From:     Simon Shutter <simon@xxxxxxxxxxx>
Sent:     Fri, 16 Mar 2007 10:36:14 -0700
To:       <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Subject:  [xsl] Variation on adjaceny list question



A few weeks ago I presented a problem in which I needed to transform a
tabular data set into a hierarchical set.  I then reframed my question
slightly to that the input is an XML representation of an adjacency list
where each <row> element has 0 or 1 parent element where the ParentID
element points to the ID element of the parent.

Sergey Dubinets provided a solution on the MSDN newsgroup that looks like
this.

For an input of :

<root>
  <row><ID>1</ID><Name>One</Name></row>
  <row><ID>2</ID><ParentID>1</ParentID><Name>Two</Name></row>
  <row><ID>3</ID><ParentID>2</ParentID><Name>Three</Name></row>
  <row><ID>4</ID><ParentID>1</ParentID><Name>Four</Name></row>
</root>

Use this stylesheet : 

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">
  <xsl:output
  version="1.0"
  indent="yes"
  omit-xml-declaration="yes"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>Tree</title>
      </head>
      <body>
        <xsl:apply-templates select="root/row[not(ParentID)]"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="row">
    <ul>
      <li>
        <xsl:value-of select="Name"/>
        <xsl:variable name="id" select="ID"/>
        <xsl:apply-templates select="../row[ParentID = $id]"/>
      </li>
    </ul>
  </xsl:template>

</xsl:stylesheet>

To produce this output :

<html>
  <head>
    <title>Tree</title>
  </head>
  <body>
    <ul>
 
<li>One<ul><li>Two<ul><li>Three</li></ul></li></ul><ul><li>Four</li></ul></l
i>
    </ul>
  </body>
</html>

However, what if I have more than one node (eg IDs 1 and 3) without a
ParentID like this:

<root>
  <row><ID>1</ID><Name>One</Name></row>
  <row><ID>2</ID><ParentID>1</ParentID><Name>Two</Name></row>
  <row><ID>3</ID><Name>Three</Name></row>
  <row><ID>4</ID><ParentID>3</ParentID><Name>Four</Name></row>
</root>

The stylesheet produces :

<html>
  <head>
    <title>Tree</title>
  </head>
  <body>
    <ul>
      <li>One<ul><li>Two</li></ul></li>
    </ul>
    <ul>
      <li>Three<ul><li>Four</li></ul></li>
    </ul>
  </body>
</html>

My question is - how can I change the stylesheet such that the two unordered
lists are combined to produce this desired output:

<html>
  <head>
    <title>Tree</title>
  </head>
  <body>
    <ul>
      <li>One<ul><li>Two</li></ul></li>
      <li>Three<ul><li>Four</li></ul></li>
    </ul>
  </body>
</html>


Thanks, Simon

Current Thread