This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Formatting elements
- To: xsl-list at mulberrytech dot com
- Subject: Re: Formatting elements
- From: Paul Tchistopolskii <paul at qub dot com>
- Date: Tue, 03 Oct 2000 22:49:27 -0700
- Organization: The Qub Group
- References: <3.0.1.32.20001003204848.009a4ca0@localhost>
- Reply-To: xsl-list at mulberrytech dot com
----- Original Message -----
From: Jeni Tennison <mail@jenitennison.com>
> <document>
> <item name='title'><text>Title field</text></item>
> <item name='bullet1'><text>some text for item 1</text></item>
> <item name='bullet2'><text>some text for item 2</text></item>
> <item name='bullet3'><text/></item>
> <item name='bullet4'><text/></item>
> <item name='bullet5'><text/></item>
> <item name='bullet6'><text/></item>
> <item name='para'><text>paragraph text</text></item>
> <item name='bullet1'><text>some text for item 1</text></item>
> <item name='bullet2'><text>some text for item 2</text></item>
> <item name='bullet3'><text/></item>
> <item name='bullet4'><text/></item>
> </document>
>
> which you want to be:
>
> <document>
> <title>Title field</title>
> <bulletlist>
> <bullet>some text for item 1</bullet>
> <bullet>some text for item 2</bullet>
> <bullet></bullet>
> <bullet></bullet>
> <bullet></bullet>
> <bullet></bullet>
> </bulletlist>
> <para>paragraph text</para>
> <bulletlist>
> <bullet>some text for item 1</bullet>
> <bullet>some text for item 2</bullet>
> <bullet></bullet>
> <bullet></bullet>
> </bulletlist>
> </document>
>
Below please find another ( pure functional ) solution.
I'll first give XSLScript notation and then will be the XSL code
( generated, as usual ). I think this should illustrate the
real value of terseness.
I think the biggest problem of this transformation is XSL verbosity,
because the transformation itself is not complex at all.
It is Composed of 2 simple steps :
If it is 'bullet' - see when 'bulletlist' ends : split on that point and
call yourself again.
I think this 'split / call yourself ' is the the core pattern which
any XSL developer should learn ( the same happens with
counters e t.c. )
There is a small 'drawback' similar to 'drawback' of my solution to
Sebastian's test6, but I'm better not to start this all again.
Whatever.
X:transform {
X:output indent="yes";
X:template = "document" {
<document>
<% !render-flat( list="item") %>
</document>
}
X:template render-flat( list ) {
<% X:if "$list" {
<% X:var type="string($list[1]/@name)" %>
<% X:if "starts-with( $type, 'bullet' )" {
<% X:var fnbul={ <% !first-non-bul( list="$list", count={1} ) %> }
%>
<bulletlist>
<% X:for-each "$list[ position() < $fnbul ]" {
<bullet> <% {.} %> </bullet>
} %>
</bulletlist>
<% !render-flat( list="$list[ not ( position() < $fnbul )]" ) %>
} else
<% X:element "{$type}" {
<% { $list[1] } %>
} %>
<% !render-flat( list="$list[ position() > 1]" ) %>
} %>
} %>
}
X:template first-non-bul( list, count ) {
<% X:if "$list" {
<% X:var type="string($list[1]/@name)" %>
<% X:if "starts-with( $type, 'bullet' )" {
<% !first-non-bul( list="$list[ position() > 1 ]", count="$count +
1" ) %>
} else {
<% {$count} %>
} %>
} else {
<% {$count} %>
} %>
}
}
Here is the XSL.
------------------------
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="document">
<document>
<xsl:call-template name="render-flat">
<xsl:with-param select="item" name="list"/>
</xsl:call-template>
</document>
</xsl:template>
<xsl:template name="render-flat">
<xsl:param name="list"/>
<xsl:if test="$list">
<xsl:variable select="string($list[1]/@name)" name="type"/>
<xsl:choose>
<xsl:when test="starts-with( $type, 'bullet' )">
<xsl:variable name="fnbul">
<xsl:call-template name="first-non-bul">
<xsl:with-param select="$list" name="list"/>
<xsl:with-param name="count">1</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<bulletlist>
<xsl:for-each select="$list[ position() < $fnbul ]">
<bullet>
<xsl:value-of select="."/>
</bullet>
</xsl:for-each>
</bulletlist>
<xsl:call-template name="render-flat">
<xsl:with-param select="$list[ not ( position() < $fnbul )]"
name="list"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$type}">
<xsl:value-of select=" $list[1]"/>
</xsl:element>
<xsl:call-template name="render-flat">
<xsl:with-param select="$list[ position() > 1]" name="list"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template name="first-non-bul">
<xsl:param name="list"/>
<xsl:param name="count"/>
<xsl:choose>
<xsl:when test="$list">
<xsl:variable select="string($list[1]/@name)" name="type"/>
<xsl:choose>
<xsl:when test="starts-with( $type, 'bullet' )">
<xsl:call-template name="first-non-bul">
<xsl:with-param select="$list[ position() > 1 ]" name="list"/>
<xsl:with-param select="$count + 1" name="count"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$count"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$count"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list