xsl-list
[Top] [All Lists]

RE: [xsl] Constructing multi-level lists - any better than this?

2007-09-15 10:07:40
Hi,

I would have done something like this (pseudo-code):

<template match="p">
        <copy />
</template>
 
<template match="l1|l2">
        <if test="preceding-sibling::*[1][self::p]">
                <ul>
                        <apply-templates select="." mode="level1" />
                </ul>
        </if>
</template>

<template match="*" mode="level1">
        <!-- terminate continuation if not l1 or l2 -->
</template>

<template match="l1" mode="level1">
        <copy />
        <apply-templates select="following-sibling::*[1]" mode="level1" />
</template>

<template match="l2" mode="level1">
        <if test="preceding-sibling::*[1][self::p or self::l1]">
                <ul>
                        <apply-templates select="." mode="level2" />
                </ul>
        </if>
        <apply-templates select="following-sibling::*[1]" mode="level1" />
</template>

<template match="*" mode="level2">
        <!-- terminate continuation if not l2 -->
</template>

<template match="l2" mode="level2">
        <copy />
        <apply-templates select="following-sibling::*[1]" mode="level2" />
</template>

But it is limited by recursion depth. On the other hand, it doesn't require 
XSLT 2.0.

Kind regards,
Geert


   
 
Drs. G.P.H. Josten
Consultant
 
 

Daidalos BV
Source of Innovation
Hoekeindsehof 1-4
2665  JZ  Bleiswijk
Tel.: +31 (0) 10 850 1200
Fax: +31 (0) 10 850 1199
www.daidalos.nl
KvK 27164984


De informatie - verzonden in of met dit emailbericht - is afkomstig van 
Daidalos BV en is uitsluitend bestemd voor de geadresseerde. Indien u dit 
bericht onbedoeld hebt ontvangen, verzoeken wij u het te verwijderen. Aan dit 
bericht kunnen geen rechten worden ontleend.
 

From: Michael Müller-Hillebrand [mailto:mmh(_at_)cap-studio(_dot_)de] 
Sent: zaterdag 15 september 2007 18:44
To: XSL-List
Subject: [xsl] 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>






--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--