Using XPATH to Get the Position of a Node in a Node Set

geoffc

By: geoffc

November 8, 2009 9:38 am

Reads: 1558

Comments:3

Rating:0

Using XPATH to get the position of a node in a node set:

Novell Identity Manager is a great tool. Lots of power, and several interesting languages are available for use.

There is XML Style sheets (XSLT) that were the first available language in DirXML 1.0. You could always call out to a Java class, so that was not all that limiting.

With the advent of NSure Identity Manager 2.0 we got access to DirXML Script, which is a great XML based language for processing XML documents. It is very readable and makes sense (in English only, sorry) to read, because the tokens, verbs, and nouns are all nicely described by their definition.

Probably the greatest strength about the DirXML Script is actually the interface that parses it, Policy Builder. There are currently two different implementations of it, one in iManager, and the other in Designer for Identity Manager.

I personally like the Designer interface better, but that is more of a preference for the widgets and the responsiveness of a thick client (Eclipse based) versus a web application, that is always, by definition, a little slower to respond.

Both are great, and what is often most powerful is that use the interface to design the rule in general. Then when you realize you need to make minor changes, you can easily flip over to the XML view and copy and paste, or edit something minor (or major) faster than you could in the interface. The best of both worlds.

One of the features both XSLT and DirXML Script offer is the ability to use the XML Path language (XPATH). The problem is Novell Identity Manager only supports XPATH 1.0, not the newer 2.0 standard, which means many searches for XPATH help will return 2.0 functions or ideas, that will not work in XPATH 1.0.

Additionally, the way Identity Manager uses XPATH is slightly different from how standard XPATH is implemented. (Usually related to the context node (see: XPATH and the context node)). This sometimes makes it hard to translate web XPATH examples into Identity Manager examples.

Additionally you do not see a lot of articles about really cool ways to use XPATH in Identity Manager. Thus I was looking to add more articles on the issue to the public mix.

One source of information about XPATH is the RFC that defines XPATH:
http://www.w3.org/TR/1999/REC-xpath-19991116

The thing is that the RFC does not really provide examples, and most web resources on XPATH are confusing since they focus on using XPATH for HTML document manipulation, which is not obvious how they might apply to XDS event documents.

Other than that, there are a couple of good sites with some examples:

I have been trying to write some articles about interesting XPATH tidbits, you can read more at:

We still need more I think, so here goes another one.

I was reading a neat web site called Stack Overflow, (www.stackoverflow.com) and looked for this interesting XPATH example I thought I would liberate (Information wants to be free after all, right?)
http://stackoverflow.com/questions/226405/find-position-of-a-node-using-xpath

When referring to a node set, it is possible to specify a couple of interesting XPATH descriptors to specify it by the node placement.

That is, if you are using an Append XML element, you need to specify an XPATH location for it. So you could say add-attr[@attr-name="Group Membership"]/value[2] to refer to the second node in the set of values. Or you could append it to the end with add-attr[@attr-name="Group Membership"]/value/last() or insert at the beginning, with add-attr[@attr-name="Group Membership"]/value/first() and whatnot.

But what if you want to know what place the node is in the list of values, how would you do figure it out via XPATH? I think I know how I would do it by looping through the node set in a for-each loop, using a counter value, and testing each value for the one I want and returning the counter value when done.

If this is a really large node set, then it probably is not very efficient to loop through the node set, and would be really cool to just do it in a magical XPATH statement.

Now to be fair, I am having trouble deciding when I would want to actually know this info in an Identity Manager context, since most multi valued attributes that are returned, while they look ordered, usually are not. Often they do not return the values in a predictable order, though they ought to return in the same order each time (as long as you use the same replica). (I.e. Usually not alphabetic, usually by the order it was added as a value). But I think it is an interesting exercise regardless. Ok, I’ll admit it, I thought it was a really cool XPATH example and just had to write about it.

To demonstrate the issue, the article I found this in, used a sample node set of:

<a>
    <b>zyx</b>
    <b>wvu</b>
    <b>tsr</b>
    <b>qpo</b>
</a>

And wanted to know the position of the <b> node that has the value of ‘tsr’.

The suggestion was an XPATH of:

count(a/b[.='tsr']/preceding-sibling::*)+1

This does not really help in an Identity Manager example, after all, what a/b in our context, so lets imagine a group membership node set, where we queried for Group membership and got back an <instance> document, that has a <attr> node, with an attribute of attr-name=”Group Membership” and a bunch of <value> nodes.

So our node set looks something like: (I grabbed this from an Active Directory driver example)

<nds dtdversion="2.2">
  <source>
    <product version="3.5.11.20080307 ">DirXML</product>
    <contact>Novell, Inc.</contact>
  </source>
  <output>
    <instance class-name="Group" src-dn="CN=Domain Admins,CN=Users,DC=Test,DC=domain">
      <attr attr-name="Group Membership">
          <value type="dn">CN=Lateefah Smith,OU=Fac,OU=19TH,DC=Test,DC=domain</value>
          <value type="dn">CN=Alonzo Duncan,OU=CustSvc,OU=NY,DC=Test,DC=domain</value>
          <value type="dn">CN=Jeanie Jones,OU=CustSvc,OU=NY,DC=Test,DC=domain</value>
          <value type="dn">CN=Armando Corona,OU=CustSvc,OU=NY,DC=Test,DC=domain</value>
          <value type="dn">CN=idmUser,CN=Users,DC=Test,DC=domain</value>
          <value type="dn">CN=Administrator,CN=Users,DC=Test,DC=domain</value>
        </add-value>
      </modify-attr>
    </modify>
  </input>
</nds>

So what would XPATH be in our example?

count(attr/value[.='$TARGET']/preceding-sibling::*)+1

(I used a variable $TARGET instead of a literal string, since I think it is a bit clearer, but you could use a literal string like this instead ‘CN=idmUser,CN=Users,DC=Test,DC=domain’ to specify the value).

The way this works is it selects the node where the value equals the string we are looking for, then goes back one node, counts the number of nodes till there, and adds one to it. (I think they used preceding-sibling plus one, because it is a built in test that lets you go back one, thus the need to add one.

Neat eh? The best use I can think of this, is really the only time I needed to really use the [x] (you know, like [0] or [2] for the zeroth or second position) notation to pick a node. I was writing direct SQL commands in the JDBC driver, like in this article: Using the JDBC Driver and Direct SQL

In that case I needed to send several SQL statements in one operation, (in the end I went back and did it all in one SQL statement once I got better at SQL, but on my first attempt I needed to do several SQL statements) and each SQL statement you want to send needs an XML node of <jdbc:sql> under a <jdbc:statement> node with the SQL statement. In which case, you want to be sure you insert it into a specific node. In that case, the ordering did matter, but I concede it is a bit of a stretch. But come on, it is a really neat XPATH example!

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Tags: ,
Categories: Uncategorized

Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment.  It just worked for at least one person, and perhaps it will be useful for you too.  Be sure to test in a non-production environment.

3 Comments

  1. By:Anonymous

    You can get away with
    count(attr/value[.='$TARGET']]/preceding::*) + 1
    saving total of 8 characters ;)

    Pekka

  2. By:dcop123

    I am a bit confused…. would XPATH be applicable on Drupal 7 or 8 also??

  3. By:geoffc

    My particular focus in this article was how to use XPATH in IDM, based on a sample XPATH given, for the more general case.

    I.e. How to take someone elses generic XPATH idea and use it in IDM.

    So your question is sort of hard to answer. I have no idea if it would work in Drupal, since I have never touched drupal (except as a user, since i think this site (Cool Solutions) is actually running on Drupal.

    In principle, sure as heck it should work in Drupal. But no idea.

Comment