[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Constructing multi-level lists - any better than this?

Subject: Constructing multi-level lists - any better than this?
From: Michael Müller-Hillebrand <mmh@xxxxxxxxxxxxx>
Date: Sat, 15 Sep 2007 18:43:31 +0200
 Constructing multi-level lists - any better than this?
Hello,

I have a working stylesheet, but it uses modes when I think it could
be a bit slimmer and maybe more flexible.

The task is to create list containers (<ul>) around list elements in
a flat element tree. I tried to follow Jeni Tennison's advice for
constructing hierarchies <http://jenitennison.com/xslt/hierarchies-
out.xml> and also evaluated xsl:for-each-group, but the latter seems
not to work very well for a stylesheet in push mode (no changes to
the element order).

To correctly group the <li1>s and <li2>s (even in the third case) in
this example I successfully used the XSL below. I found no good
enough example in the FAQs, so I dare to ask, whether there is a more
elegant solution. (I simplified the case, in reality there are
multiple elements that are either level 1 or level 2 list elements,
and I do not use starts-with() to detect element names.)

Any advice is greatly appreciated!

- Michael M|ller-Hillebrand

<?xml version="1.0" encoding="UTF-8"?>
<levels>
<p/>
<li1>1</li1>
<li1>2</li1>
<li1>3</li1>
<li1>4</li1>
<p/>
<li1>5</li1>
<li1>6</li1>
<li2>7.1</li2>
<li2>7.2</li2>
<p/>
<li2>8.1</li2>
<li2>8.2</li2>
<li1>9</li1>
<li1>10</li1>
<p/>
</levels>

---------

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

<!-- Root element -->
<xsl:template match="levels">
  <xsl:copy>
    <xsl:apply-templates />
  </xsl:copy>
</xsl:template>

<!-- Keys to identify list elements after first element -->
<xsl:key name="list12-other"
  match="*[self::*[starts-with(name(), 'li')]
    and preceding-sibling::*[1][starts-with(name(), 'li')]]"
  use="generate-id(
    preceding-sibling::*[
      starts-with(name(), 'li')
      and not(preceding-sibling::*[1][starts-with(name(), 'li')])
    ][1])" />

<xsl:key name="list2-other"
  match="li2[preceding-sibling::*[1][self::li2]]"
  use="generate-id(
    preceding-sibling::li2[
      not(preceding-sibling::*[1][self::li2])
    ][1])" />

<!-- List 1 Container-->
<xsl:template match="*[starts-with(name(), 'li')
  and not(preceding-sibling::*[1][starts-with(name(), 'li')])]"
priority="1">
  <ul level="1">
    <xsl:apply-templates mode="list1"
      select=". | key('list12-other', generate-id())" />
  </ul>
</xsl:template>
<!-- List 1 elements -->
<xsl:template match="li1" mode="list1">
  <li tag="{name()}" pos="{position()}">
    <xsl:apply-templates />
  </li>
</xsl:template>

<!-- or List 2 Container-->
<xsl:template match="li2[not(preceding-sibling::*[1][self::li2])]"
  mode="list1" priority="1">
  <ul level="2">
    <xsl:apply-templates mode="list2"
      select=". | key('list2-other', generate-id())" />
  </ul>
</xsl:template>
<!-- List 2 elements -->
<xsl:template match="li2" mode="list2">
  <li tag="{name()}" pos="{position()}">
    <xsl:apply-templates />
  </li>
</xsl:template>

<!-- skip list elements when matched outside list -->
<xsl:template match="li2" mode="list1"/>
<xsl:template match="*[starts-with(name(), 'li')]"/>

<!-- all other nodes -->
<xsl:template match="node()">
  <xsl:copy>
    <xsl:apply-templates />
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.