This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: multi-levels counter
- From: Jeni Tennison <jeni at jenitennison dot com>
- To: "Allen Chu" <achu at dscs dot com>
- Cc: xsl-list at lists dot mulberrytech dot com
- Date: Mon, 10 Jun 2002 16:46:18 +0100
- Subject: Re: [xsl] multi-levels counter
- Organization: Jeni Tennison Consulting Ltd
- References: <000001c21091$3733a8f0$1401a8c0@dscs.com>
- Reply-to: xsl-list at lists dot mulberrytech dot com
Hi Allen,
> How can I keep a counter for each <text> segment? Thanks in
> advance!!
The method that most closely resembles your description is to turn the
natural rule-based processing model of XSLT into a procedural one by
stepping through the elements one by one, passing a parameter down
through each call.
Doing that is quite ugly and can make it difficult to get a structured
result, so it's probably easier to rephrase what you want to do to
"How can I assign a number to each text segment based on its position
relative to all the other text segments in the document?"
There's a natural solution to that in XSLT, namely xsl:number. Doing:
<xsl:template match="text">
<xsl:number level="any" format="1." />
<xsl:value-of select="." />
</xsl:template>
will produce output with numbers like '1.', '2.' for each text element
in the document.
xsl:number actually works by, for each text element, looking at all
the preceding nodes in the tree, finding text elements amongst them,
and counting them. That can be quite a lot of node visits in a large
document, which would be quite slow. If speed is an issue, then you
could try a partial version of the step-by-step method mentioned
above, which would be something like:
<xsl:template match="*">
<!-- $ntext keeps track of the number of text elements so far -->
<xsl:param name="ntext" select="0" />
<!-- create a copy of this element -->
<xsl:copy>
<xsl:copy-of select="@*" />
<!-- pass $ntext on to the first child of this element -->
<xsl:apply-templates select="*[1]">
<xsl:with-param name="ntext" select="$ntext" />
</xsl:apply-templates>
</xsl:copy>
<!-- move on to the next sibling of this element, adding the number
of text element children of this one to the count -->
<xsl:apply-templates select="following-sibling::*[1]">
<xsl:with-param name="ntext" select="$ntext + count(.//text)" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="text">
<xsl:param name="ntext" select="0" />
<!-- give the number, followed by the text segment -->
<xsl:value-of select="$ntext" />. <xsl:value-of select="." />
<!-- move on to the next sibling of this element, adding one to the
count -->
<xsl:apply-templates select="following-sibling::*[1]">
<xsl:with-param name="ntext" select="$ntext + 1" />
</xsl:apply-templates>
</xsl:template>
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list