[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

RE: line numbering

Subject: RE: line numbering
From: "Andrew Welch" <ajwelch@xxxxxxxxxxxxxxx>
Date: Thu, 5 Aug 2004 15:17:05 +0100
line numbering
> Hi there,
>
> I have some poems marked up something like:
>
> <body>
> <div type="poem">
> <lg type="stanza">
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> </lg>
> <lg type="stanza">
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> </lg>
> <p>This is something not counted as a line</p>
> <lg type="stanza">
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> <l>This is a line of verse</l>
> </lg>
> </div>
> <!-- and multiple poem div's like this here... -->
> </body>
>
> What I want to end up with is for each line to be
> given an @id in the html output like:
> <span id="poem3line10">This is a line of verse <span
> class="number">10</span></span>
>
> <xsl:template match="l">
> <xsl:variable name="linenumber"
> select="count(preceding-sibling::l)+1"/>
> <span class="line"
> id="line{$linenumber}"><xsl:apply-templates /></span> </xsl:template>
>
> But now I need to account for two factors:
> a) that the linenumbering needs to take account of
> the existence of the line-groups (lg) and that it
> should only count back within it's own <div> ancestor.
> b) that I want to number the lines every 5 lines.
>
> Is position() a better way to do this than counting the
> preceding-sibilings?

If you have a large input xml you may find counting preceding siblings
to be expensive, and that its better to do the numbering in a variable
in an initial pass of the xml.  For example using this stylesheet:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  extension-element-prefixes="exsl">

<xsl:output indent="yes"/>

<xsl:key name="lines" match="line" use="@id"/>

<xsl:variable name="lines-rtf">
  <xsl:for-each select="/body/div">
    <poem number="{position()}">
      <xsl:for-each select="lg/l">
        <line id="{generate-id()}" number="{position()}"/>
      </xsl:for-each>
    </poem>
  </xsl:for-each>
</xsl:variable>
<xsl:variable name="lines" select="exsl:node-set($lines-rtf)"/>

<xsl:template match="/">
 <div>
   <xsl:apply-templates select="/body/div/lg/l"/>
 </div>
</xsl:template>

<xsl:template match="l">
  <xsl:variable name="genId" select="generate-id()"/>
  <span>
    <xsl:attribute name="id">
      <xsl:for-each select="$lines">
         <xsl:for-each select="key('lines',$genId)">
           <xsl:value-of
select="concat('poem',parent::poem/@number,'line',@number)"/>
         </xsl:for-each>
      </xsl:for-each>
    </xsl:attribute>

    <xsl:value-of select="."/>

    <xsl:if test="position() mod 5 = 1">
      <span class="number">
        <xsl:for-each select="$lines">
          <xsl:value-of select="key('lines',$genId)/@number"/>
        </xsl:for-each>
      </span>
    </xsl:if>
  </span>
</xsl:template>

</xsl:stylesheet>

With your example xml gives this result:

<div>
   <span id="poem1line1">This is a line of verse<span
class="number">1</span>
   </span>
   <span id="poem1line2">This is a line of verse</span>
   <span id="poem1line3">This is a line of verse</span>
   <span id="poem1line4">This is a line of verse</span>
   <span id="poem1line5">This is a line of verse</span>
   <span id="poem1line6">This is a line of verse<span
class="number">6</span>
   </span>
   <span id="poem1line7">This is a line of verse</span>
   <span id="poem1line8">This is a line of verse</span>
   <span id="poem1line9">This is a line of verse</span>
   <span id="poem1line10">This is a line of verse</span>
   <span id="poem1line11">This is a line of verse<span
class="number">11</span>
   </span>
   <span id="poem1line12">This is a line of verse</span>
</div>

(I'm not sure if the line numbering 'every five lines' is correct, I
would guess you would want 1,5,10,15 and so on, so a bit more logic is
required there)

In the stylesheet all the numbering is done using the position()
function as the nested for-each's iterate over xml.  The variable is
then queried using a key to maximise performance when accessing the
variable.  This minimal stylesheet should be O(2n) complexity, counting
preceding-siblings would be slightly worse in this case.


cheers
andrew

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.