Subject: Re: [xsl] Constructing multi-level lists - any better than this? From: Abel Braaksma <abel.online@xxxxxxxxx> Date: Sun, 16 Sep 2007 17:07:13 +0200 |
<li1>test1</li1> <li3>test3</li3>
<ul level="1"> <li tag="li1" pos="1">test1</li> <ul level="2"> <ul level="3"> <li tag="li3" pos="1">test3</li> </ul> </ul> </ul>
<xsl:template match="p" mode="new"> <xsl:copy /> <xsl:apply-templates select="following-sibling::*[1]" mode="new" /> </xsl:template>
<!-- true for a node of type <liX> where X is a number --> <xsl:function name="fn:is-li"> <xsl:param name="node" /> <xsl:sequence select="starts-with(local-name($node), 'li')" /> </xsl:function>
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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Constructing multi-level , Andrew Welch | Thread | [xsl] Hide and show rows, Jonathan Dias |
RES: [xsl] Hide and show rows, Jonathan Dias | Date | [xsl] passing xml strings to xslt u, John Smith |
Month |