• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 9722
  • 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 BormansInformation ArchitectCommented:
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
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
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 BormansInformation ArchitectCommented:
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 BormansInformation ArchitectCommented:
welcome
0
 
rogerperkinsCommented:
position()
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

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