xsl-list
[Top] [All Lists]

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

2007-09-17 02:10:05
On 9/17/07, Michael Müller-Hillebrand <mmh(_at_)cap-studio(_dot_)de> wrote:
Andrew: I was longing for a solution with some XSLT2 but I have a
problem with group-starting-with="*[self::p]", because the p elements
are just placeholders for any other element that does not belong to a
list and may appear any number of times. So the source XML is a
mixture of some non-list elements followed by some list elements
followed by some non-list elements... The source may even begin with
some list elements. Perhaps my example was too much stripped down.
This would have illustrated it better:

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


Ah, in which case you fallen into the trap of describing your
potential solution ("groups should start with a <p>") rather than the
problem itself ("adjacent <li1> and <li2> should be grouped")  :)

So with that mind this looks like a good use for group-adjacent, which
turns out to be a better solution than the previous one I posted
anway:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="levels">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="self::li1
or self::li2">
                <xsl:choose>
                    <xsl:when test="self::li1 or self::li2">
                        <ul level="1">
                            <xsl:for-each-group
select="current-group()" group-adjacent="name()">
                                <xsl:choose>
                                    <xsl:when test="self::li1">
                                        <xsl:apply-templates
select="current-group()"/>
                                    </xsl:when>
                                    <xsl:when test="self::li2">
                                        <ul level="2">
                                            <xsl:apply-templates
select="current-group()"/>
                                        </ul>
                                    </xsl:when>
                                </xsl:choose>
                            </xsl:for-each-group>
                        </ul>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:copy-of select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="li1|li2">
        <li tag="{name()}" pos="{position()}">
            <xsl:apply-templates/>
        </li>
    </xsl:template>

</xsl:stylesheet>

It's a shame you have to effectively repeat the group-adjacent test in
the xsl:when to determine if the current-group() is a matching-group
or a non-matching-group.... I guess if the test was really complex you
could change the outer xsl:when to be:

test="current-grouping-key() eq true"

or just

test="current-grouping-key()"

to be the equivalent of

test="is-matching-group()"

But then that would only work when the grouping key was a boolean...
Anyway, I hope this is useful - it's the first time I've ever needed
to use group-adjacent :)


cheers
-- 
Andrew Welch
http://andrewjwelch.com
Kernow: http://kernowforsaxon.sf.net/

--~------------------------------------------------------------------
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>
--~--

<Prev in Thread] Current Thread [Next in Thread>