• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 9713
  • Last Modified:

Count nodes, return current node position

Hi!

It has been a while since I worked with XSLT, and now I have severe brain damage from switching back and forth working with JavaScript and PHP.

Anyhow, I need some help with XSLT/Xpath, if anyone has some time.

I need to get the current node number.

Let's say there is 5 nodes with the name sugarDaddy, I need to know which number I am currently at (when applying a template).
0
numbers1to9
Asked:
numbers1to9
  • 5
  • 3
1 Solution
 
Geert BormansCommented:
use xsl:number

    <xsl:template match="sugarDaddy">
        <xsl:number count="sugarDaddy" level="any" />
    </xsl:template>

cheers

Geert
0
 
numbers1to9Author Commented:
Thanks for your quick reply Geert.

I am currently doing that... Well, something like that...

<xsl:number level="any" count="/root//$x" />

Where X is the name of the node (the number function is in a template).

Any ideas?
0
 
numbers1to9Author Commented:
I've been testing some things and it seems that I have to give a little bit more info...

This is exactly what I am trying to do:

<xsl:call-template name="template">
    <xsl:with-param name="node" select="/root/node1/node2/x"/>
    <xsl:with-param name="count" select="/root//x"/>
</xsl:call-template>

<xsl:template name="template">
  <xsl:for-each select="$node">
    <xsl:number level="any" count="$count" />
  </xsl:for-each>
</xsl:template>

The above doesn't seem to work. If I however remove the "$count" and set the count value to "/root//x" things seem to go forwards...

I need some fresh ideas on how to solve this, it seems...
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
numbers1to9Author Commented:
I do not get it, can you not pass a variable in the @count ? Why? God why?...
0
 
numbers1to9Author Commented:
Well, I took care of the problem from a different angle... I think...

I will however leave this question open ('cause I ain't got m'self an answer).

Anyway, anyone that could answer the question:

"Why you can't pass a variable through xsl:number/count()"

Got themselves a 500 points * A. Couldn't be simpler could it?

0
 
Geert BormansCommented:
Hi numbers1to9,

sorry for leaving you on this, I went to bed not so long after my initial post (I am on CET, 1AM ain't that bad :-)

You can't simply pass nodes or variables to xsl:number,
cause xsl:number counts nodes at the context node
so your observation is right that you need to switch to the context in the template to get the count right
<xsl:template name="template">
  <xsl:for-each select="$node">
...
Now (...) is in the context of $node and does get the count right

The other problem you are experiencing has nothing to do with xsl:number but is a more general issue
xsl:number/@count takes an XPath expression, not a string value
In XSLT, there is no such thing as dynamically evaluated XPaths
If you pass an XPath, like this
 <xsl:with-param name="count" select="/root//x"/>
not the string "/root//x" is passed but the nodeset of all 'x' nodes found at any depth below the node 'root' that is a child of the current context will be passed
If you wanted to pass the XPath expression a a string (so avoid early evaluation), you need to do this (add single quotes)
 <xsl:with-param name="count" select="'/root//x'"/>
but that will not help you, since the string will not be evaluated as a dynamic XPath in the template

There are ways around this,
you could compare the name of an element (which is a string) to the variable string in a predicate in an XPath
(that is as close as dynamic XPaths as you will ever get)
Here is an example (note that I pass the element name as a string with single quotes)
This technique will not work if you wanted root//x instead of x.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <xsl:call-template name="template">
            <xsl:with-param name="node" select="/root/node1/node2/x"/>
            <xsl:with-param name="count" select="'x'"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="template">
        <xsl:param name="node"/>
        <xsl:param name="count"/>
        <xsl:for-each select="$node">
            <xsl:number level="any" count="*[name() = $count]" />
        </xsl:for-each>
    </xsl:template>
   
</xsl:stylesheet>

cheers

Geert
0
 
numbers1to9Author Commented:
While I must say that sleep is for the week, you sure are great!

Thanks for your explanation and your example. I used a different method from the one you gave; magic--that's right magic.

I was so tired last night so I just moved around stuff until it worked. Actually I just "for-each"-ed the node in question and used simple number@level=any to get the position, yeah I know, isn't it funny? -- one could have nothing less than a love/hate relation to the X-family.

But I have saved your example as a fall-back if [when] my method bits the dust. I was looking for a Xpath expression similar the one you gave (count="*[name() = $count]") I just couldn't remember enough of Xpath to do that (getElementById in PHP/JavaScript [DOM] sure makes you lazy ;))

Cheers, alcohol and bloody broken glass!

0
 
Geert BormansCommented:
welcome
0
 
rogerperkinsCommented:
position()
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 5
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now