Re: [xsl] Dealing without global counters

Subject: Re: [xsl] Dealing without global counters
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Wed, 12 Nov 2003 01:57:10 -0700
It occured to me that a slightly more efficient way to get the textual value
of of a number would be similar to what Dimitre mentioned earlier...

Adding this to the top of your stylesheet
<xsl:stylesheet
 version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:textValue="my::textValue"
 exclude-result-prefixes="textValue"
>

 <textValue:textValueofNumber>
  <number value="1">First</number>
  <number value="2">Second</number>
  <number value="3">Third</number>
  <number value="4">Fourth</number>
  <number value="5">Fifth</number>
  <number value="6">Sixth</number>
  <number value="7">Seventh</number>
 </textValue:textValueofNumber>

 <xsl:variable name="textValueofNumber"
select="document('')/*/textValue:*"/>

and then using this for your "textValueofNumber" template...

<xsl:template name="textValueofNumber">
  <xsl:param name="position"/>
  <xsl:value-of select="$textValueofNumber/*[@value=$position]"/>
 </xsl:template>

Makes the whole process a lot less expensive, much more efficient, and WAY
easier to maintain!

Best regards!

M.

----- Original Message ----- 
From: "M. David Peterson" <m.david@xxxxxxxxxx>
To: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Wednesday, November 12, 2003 12:59 AM
Subject: Re: [xsl] Dealing without global counters


> A solution that might add a bit of efficiency as well as give you the
> ability to use the textual representation of the numbers (the way you had
it
> in your desired output) is as follows...
>
> the following template outputs:
>
> db[1]=new dbRecord(Chapter 1)
> db[2]=new dbRecord( First Paragraph testPara_one )
> db[3]=new dbRecord( Second Paragraph testPara_two )
> db[4]=new dbRecord( Third Paragraph testPara_three )
> db[5]=new dbRecord( Fourth Paragraph testPara_four )
> db[6]=new dbRecord( First  Image testImage_one )
> db[7]=new dbRecord( Second  Image testImage_two )
> db[8]=new dbRecord( First  Table testTable )
>
> when using the input:
>
> <chapters>
> <chapter>
>     <para>testPara_one
>     </para>
>     <para>testPara_two
>     </para>
>     <image>testImage_one
>     </image>
>     <para>testPara_three
>     </para>
>     <image>testImage_two
>     </image>
>     <table>testTable
>     </table>
>     <para>testPara_four
>     </para>
> </chapter>
> </chapters>
>
> The template is as follows...
>
> <xsl:template match="/">
>   <xsl:apply-templates/>
>  </xsl:template>
>
>  <xsl:template match="chapters/chapter">
>
>  db[1]=new dbRecord(Chapter <xsl:number/>)<br/>
>
>  <xsl:for-each select="para">
>  <xsl:variable name="count"><xsl:number/></xsl:variable>
>   db[<xsl:value-of select="$count + 1"/>]=new dbRecord(
>   <xsl:call-template name="textValueofNumber">
>    <xsl:with-param name="position">
>     <xsl:number/>
>    </xsl:with-param>
>   </xsl:call-template>
>   Paragraph&#160;<xsl:value-of select="."/>)<br/>
>
>  </xsl:for-each>
>
>  <xsl:for-each select="image">
>  <xsl:variable name="count"><xsl:number/></xsl:variable>
>  <xsl:variable name="paraCount"><xsl:value-of
> select="count(../child::para)"/></xsl:variable>
>   db[<xsl:value-of select="$count + $paraCount + 1"/>]=new dbRecord(
>   <xsl:call-template name="textValueofNumber">
>    <xsl:with-param name="position">
>     <xsl:number/>
>    </xsl:with-param>
>   </xsl:call-template>
>   &#160;Image&#160;<xsl:value-of select="."/>)<br/>
>  </xsl:for-each>
>
>
>  <xsl:for-each select="table">
>  <xsl:variable name="count"><xsl:number/></xsl:variable>
>  <xsl:variable name="childCount"><xsl:value-of
> select="count(../child::*)"/></xsl:variable>
>   db[<xsl:value-of select="$count + $childCount"/>]=new dbRecord(
>   <xsl:call-template name="textValueofNumber">
>    <xsl:with-param name="position">
>     <xsl:number/>
>    </xsl:with-param>
>   </xsl:call-template>
>   &#160;Table&#160;<xsl:value-of select="."/>)<br/>
>  </xsl:for-each>
>
>  </xsl:template>
>
>  <xsl:template name="textValueofNumber">
>
>   <xsl:param name="position"/>
>
>   <xsl:choose>
>    <xsl:when test="$position = '1'">
>     First
>    </xsl:when>
>    <xsl:when test="$position = '2'">
>     Second
>    </xsl:when>
>    <xsl:when test="$position = '3'">
>     Third
>    </xsl:when>
>    <xsl:when test="$position = '4'">
>     Fourth
>    </xsl:when>
>
>     ... etc... through the reach of numbers you think you will need.
>
>   </xsl:choose>
>
>  </xsl:template>
>
> Best of luck!
>
> M.
>
> ----- Original Message ----- 
> From: "Jeni Tennison" <jeni@xxxxxxxxxxxxxxxx>
> To: "Robert Ogden" <Robert.Ogden@xxxxxxxx>
> Cc: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
> Sent: Wednesday, November 12, 2003 12:11 AM
> Subject: Re: [xsl] Dealing without global counters
>
>
> > Hi Robert,
> >
> > > Output (this output is a javascript array for an expandable TOC)
> > > db[1]=new dbRecord(chapter stuff)
> > > db[2]=new dbRecord(first para stuff)
> > > db[3]=new dbRecord(second para stuff)
> > > db[4]=new dbRecord(third para stuff)
> > > db[5]=new dbRecord(fourth para stuff)
> > > db[6]=new dbRecord(first image stuff)
> > > db[7]=new dbRecord(second image stuff)
> > > db[8]=new dbRecord(first table stuff)
> > >
> > > What I want to do is output a chapter, all text in a chapter, then
> > > all images for a chapter, and lastly all tables for a chapter. This
> > > is done repetitively for each chapter.
> >
> > A simple-minded solution might be the following. You can calculate the
> > number for a chapter using <xsl:number> with level="any" (counting
> > elements at any level in the document) and with the count attribute
> > matching those elements you're interested in counting: chapter, paras,
> > tables and images.
> >
> > Once you've output the line for the chapter, you can go on to process
> > its <para> children, then its <image> children, then its <table>
> > children. When processing the <para> elements, you want to start
> > counting from the number for the chapter; when processing the <image>
> > elements, you want to start counting from the number for the chapter
> > plus the number of <para> children the chapter has; similarly, when
> > processing the <table> children, you want to start counting from the
> > number for the chapter plus the number of <para> or <image> children
> > the chapter has:
> >
> > <xsl:template match="chapter">
> >   <xsl:variable name="number">
> >     <xsl:number level="any" count="chapter | para | table | image" />
> >   </xsl:variable>
> >
> >   <xsl:value-of
> >     select="concat('db[', $number, ']=new dbRecord(chapter
stuff)&#xA;')"
> />
> >
> >   <xsl:apply-templates select="para">
> >     <xsl:with-param name="start" select="$number" />
> >   </xsl:apply-templates>
> >   <xsl:apply-templates select="image">
> >     <xsl:with-param name="start" select="$number + count(para)" />
> >   </xsl:apply-templates>
> >   <xsl:apply-templates select="table">
> >     <xsl:with-param name="start" select="$number + count(para | image)"
/>
> >   </xsl:apply-templates>
> > </xsl:template>
> >
> > When it comes to processing the <para>, <image> and <table> elements,
> > the $start parameter gives you the starting number. The number for the
> > <para>, <image> or <table> is this starting number plus the number for
> > the particular <para>, <image> or <table>, which you can again get via
> > the <xsl:number> instruction:
> >
> > <xsl:template match="para | image | table">
> >   <xsl:param name="start" select="0" />
> >   <xsl:variable name="number"><xsl:number /></xsl:variable>
> >   <xsl:value-of
> >     select="concat('db[', $start + $number,
> >                    ']=new dbRecord(', name(), ' stuff)&#xA;')" />
> > </xsl:template>
> >
> >
> > This approach isn't very efficient -- numbering with <xsl:number>
> > seldom is, especially with level="any" -- but that might not be a
> > problem for you.
> >
> > In XSLT 2.0, you can create a sequence that contains the elements that
> > you want to process in the correct order, and then iterate over that
> > sequence, using the position() function to provide the relevant
> > numbers. The code would look something like:
> >
> >   <xsl:variable name="elements" as="element()*">
> >     <xsl:for-each select="chapter">
> >       <xsl:sequence select="(., para, image, table)" />
> >     </xsl:for-each>
> >   </xsl:variable>
> >   <xsl:for-each select="$elements">
> >     <xsl:value-of
> >       select="concat('db[', xs:string(position()),
> >                      ']=new dbRecord(', name(), ' stuff)&#xA;')" />
> >   </xsl:for-each>
> >
> > Cheers,
> >
> > Jeni
> >
> > ---
> > Jeni Tennison
> > http://www.jenitennison.com/
> >
> >
> >  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> >
>
>
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
>


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread