RE: [xsl] <xsl:number> starting at a preceding-sibling

Subject: RE: [xsl] <xsl:number> starting at a preceding-sibling
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 20 Jan 2009 00:04:36 -0000
Try this:

<xsl:template match="level1">
<xsl:copy>
  <xsl:number level="any" from="root" format="1"/>
</xsl:copy>
</xsl:template>

<xsl:template match="level2">
<xsl:copy>
  <xsl:number level="any" from="level1" format="a"/>
</xsl:copy>
</xsl:template>

<xsl:template match="level3">
<xsl:copy>
  <xsl:number level="any" from="level2" format="i"/>
</xsl:copy>
</xsl:template>

The surprise here (and it took me a while to grasp it) is that level="any"
is needed even though you're counting siblings. This is because the "from"
pattern doesn't work the way you want it to with level="single".

Michael Kay
http://www.saxonica.com/

> -----Original Message-----
> From: Spencer Tickner [mailto:spencertickner@xxxxxxxxx] 
> Sent: 19 January 2009 23:04
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] <xsl:number> starting at a preceding-sibling
> 
> Hi List and thanks in advance for the help.
> 
> I'm attempting to number some flat xml using xslt 2.0 and am 
> struggling a bit. Given:
> 
> <root>
> 	<level1></level1>
> 	<level1></level1>
> 	<level2></level2>
> 	<level3></level3>
> 	<level2></level2>
> 	<level1></level1>
> 	<level2></level2>
> 	<level3></level3>
> </root>
> 
> I need to number each level based on it's preceding-sibling 
> so it would look like:
> 
> <root>
> 	<level1>1</level1>
> 	<level1>2</level1>
> 	<level2>a</level2>
> 	<level3>i</level3>
> 	<level2>b</level2>
> 	<level1>3</level1>
> 	<level2>a</level2>
> 	<level3>i</level3>
> </root>
> 
> Counting <level1> is easy with <xsl:number> but the template 
> for <level2> and <level3>. Stylesheet is below, template for 
> level3 is ommited as it will hinge on solving the template 
> for level2 (I know all the variables are pretty ugly):
> 
> <?xml version='1.0'?>
> <xsl:stylesheet version="1.0" 
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> 
> <xsl:template match="/">
> 	<xsl:apply-templates/>
> </xsl:template>
> 
> 
> <xsl:template match="*">
> 	<xsl:copy>
> 		<xsl:copy-of select="@*"/>
> 		<xsl:apply-templates/>
> 	</xsl:copy>
> </xsl:template>
> 
> <xsl:template match="level1">
> <xsl:copy>
> <xsl:number count="level1" level="single" format="1"/> 
> </xsl:copy> </xsl:template>
> 
> <xsl:template match="level2">
> 	<xsl:variable name="cousins" select="preceding-sibling::*"/>
> 	<xsl:variable name="num">
> 		<xsl:value-of
> select="count($cousins[last()]/preceding-sibling::*[not(follow
> ing-sibling::level1)][name()
> = 'level2'])"/>
> 	</xsl:variable>
> 	<xsl:variable name="renum">
> 		<xsl:choose>
> 		<xsl:when test="$cousins[last()]/name() = 
> name(.)"><xsl:value-of
> select="number($num) + 2"/></xsl:when>
> 		<xsl:otherwise><xsl:value-of 
> select="number($num) + 1"/></xsl:otherwise>
> 		</xsl:choose>
> 	</xsl:variable>
> 	<xsl:copy>
> 	<xsl:number value="$renum" format="a"/>	
> 	</xsl:copy>
> </xsl:template>
> 
> </xsl:stylesheet>
> 
> 
> Any advice would be appreciated.
> 
> Thanks,
> 
> Spencer

Current Thread