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

RE: Counting nodes efficiently

Subject: RE: Counting nodes efficiently
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Thu, 19 Feb 2004 02:19:32 -0800 (PST)
xsl counting nodes
> >  Greetings.
> >  
> >  I've been using Jeni's method from the XSLT FAQ to assign 
> >  unique id's to 
> >  nodes. In order to speed things up, can anyone think of a way 
> >  that I could 
> >  store the running totals for the different nodes, rather than 
> >  having to 
> >  call the count() function repeatedly? A generalized method 
> >  would obviously 
> >  be the best, so that it could be applied to any arbitrary set 
> >  of nodes, 
> >  but I don't know if this is even possible.
> >  
> >  <xsl:template match="*">
> >     <xsl:variable name="name" select="name()" />
> >     <xsl:element name="{name()}">
> >       <xsl:attribute name="id">
> >         <xsl:value-of select="concat($name, '-',
> >         count(preceding::*[name()= $name]) +
> >         count(ancestor::*[name()= $name]))" />
> >       </xsl:attribute>
> >       <xsl:apply-templates />
> >     </xsl:element>
> >  </xsl:template>
> 
> 3 ways:
> 
> 1.  Create a node-set by selecting all the elements you wish to count
> and numbering them using position().  You can then query into this
> node-set using the generate-id() function to get the correct number for
> the element you're processing.  This only requies one pass of the data
> so its quite efficient.
> 
> 2.  Write a SAX Filter in java that numbers the elements on their way
> into the transform.  You can then select this number as if it was
> already in the data.
> 
> 3.  If you are using saxon, you can substring the value returned from
> generate-id() after the 'e', as the generated id's take form 'dxxeyy'
> where d is the document number and e is the element number.

As pointed out earlier, just using generate-id() probably solves the
original problem.

I will show here one solution to the problem, because it is interesting,
simple and uses and important xslt design pattern.

In this and similar problems one can re-use the identity transformation,
which processes strictly one node at a time (would a native English
speaker, please, suggest a good name? The best I could arrive at was "one
node at a time identity transformation"):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>
 
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()[1]"/>
    </xsl:copy>
    <xsl:apply-templates select="following-sibling::node()[1]"/>
  </xsl:template>

</xsl:stylesheet>

This transformation produces the same results as the more well-known
identity rule.

The difference is that we now have the finest possible grain-level of
controll as every xsl:apply-templates instruction above always selects at
most one node.

It is trivial to add parameters and to override the one-at-a-time identity
for elements. Thus we finally have:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>
 
  <xsl:template match="@* | node()">
    <xsl:param name="pnAncestors" select="0"/>
    <xsl:param name="pnPreceding" select="0"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()[1]">
        <xsl:with-param name="pnAncestors" 
                        select="$pnAncestors+1"/>
        <xsl:with-param name="pnPreceding"
                        select="$pnPreceding"/>
      </xsl:apply-templates>
    </xsl:copy>
    <xsl:apply-templates select="following-sibling::node()[1]">
      <xsl:with-param name="pnAncestors" 
                      select="$pnAncestors"/>
      <xsl:with-param name="pnPreceding"
                      select="$pnPreceding+1"/>
          
    </xsl:apply-templates>
  </xsl:template>
  
  <xsl:template match="*">
    <xsl:param name="pnAncestors" select="0"/>
    <xsl:param name="pnPreceding" select="0"/>
    
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:attribute name="_id">
        <xsl:value-of select=
                    "concat(name(), '_',
                            $pnAncestors, '_', 
                            $pnPreceding 
                            )"/>
      </xsl:attribute>
    </xsl:copy>
    <xsl:apply-templates select="node()[1]">
      <xsl:with-param name="pnAncestors" 
                      select="$pnAncestors+1"/>
      <xsl:with-param name="pnPreceding"
                      select="$pnPreceding"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="following-sibling::node()[1]">
      <xsl:with-param name="pnAncestors" 
                      select="$pnAncestors"/>
      <xsl:with-param name="pnPreceding"
                      select="$pnPreceding+1"/>
          
    </xsl:apply-templates>
    
  </xsl:template>

</xsl:stylesheet>

This transformation is not long, it can be written almost mechanically, it
makes exactly one pass over the tree and it has a linear time complexity
(checked with inputs of different size).


Cheers,

Dimitre Novatchev 
FXSL developer,

http://fxsl.sourceforge.net/ -- the home of FXSL
Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html




__________________________________
Do you Yahoo!?
Yahoo! Mail SpamGuard - Read only the mail you want.
http://antispam.yahoo.com/tools

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


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.