|
Subject: [xsl] Constructing multi-level lists - any better than this? From: Michael Müller-Hillebrand <mmh@xxxxxxxxxxxxx> Date: Sat, 15 Sep 2007 18:43:31 +0200 |
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.)
<?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>| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [xsl] Passing array to Jscript , bryan rasmussen | Thread | RE: [xsl] Constructing multi-level , Geert Josten |
| [xsl] Fuzzy analyze-string, mozer | Date | RE: [xsl] Constructing multi-level , Geert Josten |
| Month |