I submitted this as an article to Cool Solutions, and it will eventually
be published, but to get it out there sooner, in the hopes it helps
someone, here is the text of the article:

Examples of using XPATH in Identity Manager:

Novell Identity Manager originally started as Novell DirXML and required
all work to be done in XSLT (XML Style sheets). XSLT is powerful
language but not my personal favorite language to work with.

With the release of Novell NSure Identity Manager 2.0 we saw the advent
of DirXML Script an XML based language designed for the task of managing
XML event documents. With each release of Identity Manager since, it
has gotten better and better.

Just for the heck of it, I even wrote this article trying to track down
what you can only do in XSLT at the moment, with the goal of chipping
away at that list, where possible!

http://www.novell.com/communities/no...-dirxml-script

There have been new features that make life a lot easier, and new tokens
that are very powerful.

The nicest thing about using DirXML Script is that the management tools,
iManager with the Identity Manager snapins, or Designer for Identity
Manager (an Eclipse based tool for offline editing of a project) parse
the XML into a really nice GUI interface that allows you to type it free
form in XML, manipulate it in a GUI, or any combination of both. In
fact, sometimes, due to the way nested items (if then code blocks, or
for each loops) are shown in the GUI it is easier to fix things by
switching over to the XML view and working there.

Some examples of the various tokens and things that can be done with
DirXML Script are:
http://www.novell.com/communities/no...matching-objec
http://www.novell.com/communities/no...entity-manager
http://www.novell.com/communities/no...entity-manager
http://www.novell.com/communities/no...entity-manager
http://www.novell.com/communities/no...entity-manager
http://www.novell.com/communities/no...onality-idm-35
http://www.novell.com/communities/no...tion-attribute
http://www.novell.com/communities/no...-tokens-idm-35
http://www.novell.com/communities/no...e-new-features
http://www.novell.com/communities/no...-policy-option

One of the languages that has been available inside XSLT and DirXML
Script is called XPATH, the XML Path language, which is described here:
http://www.w3.org/TR/1999/REC-xpath-19991116

However there is just not enough out there in terms of how to use XPATH
in an Identity Manager context for people learning Identity Manager.

I have been working hard on that topic, and you can read some of my
articles on the topic at:

XPATH General Concepts:
http://www.novell.com/communities/no...entity-manager
http://www.novell.com/communities/no...d-context-node
http://www.novell.com/communities/no...xpath-and-math
http://www.novell.com/communities/no...ath-statements
http://www.novell.com/communities/no...h-context-node
http://www.novell.com/communities/no...entity-manager

XPATH Cool tips:
http://www.novell.com/communities/no...ciation-values
http://www.novell.com/communities/no...xpath-nodesets
http://www.novell.com/communities/no...n-values-xpath
http://www.novell.com/communities/no...-node-node-set

http://www.novell.com/communities/no...a-mapping-rule
http://www.novell.com/communities/no...duce-map-token


I thought a general article with basic examples of various things you
might do in XPATH would be useful, so lets see how this effort goes.

I personally find that seeing the XML document I am trying to apply my
XPATH too makes it easier to visualize, understand, and work with. Here
is a sample XDS (Novell's XML dialect for Identity). Lets use a simple
add document, that has a bunch of interesting things in it.

<nds dtdversion="3.5" ndsversion="8.x">
<source>
<product version="3.6.1.4427">DirXML</product>
<contact>Novell, Inc.</contact>
</source>
<input>
<add class-name="User" cached-time="20101213201759"
event-id="osg900lnx#20101213201759#1#1"
qualified-src-dn="O=acme\OU=Users\OU=Applications\CN=listuser"
src-dn="\ACME-IDV\acme\Users\Applications\listuser" src-entry-id="37777"
dest-dn="\ACME-IDV\acme\Users\Applications\listuser">
<association state="migrate"></association>
<add-attr attr-name="Full Name">
<value timestamp="1292271432#40" type="string">List Server
User</value>
</add-attr>
<add-attr attr-name="Given Name">
<value timestamp="1292271432#41" type="string">List Server</value>
</add-attr>
<add-attr attr-name="L">
<value timestamp="1292271479#1" type="string">Somewhere</value>
</add-attr>
<add-attr attr-name="Login Disabled">
<value timestamp="1292271432#25" type="state">false</value>
</add-attr>
<add-attr attr-name="nspmDistributionPassword"><!-- content
suppressed -->
</add-attr>
<add-attr attr-name="Surname">
<value timestamp="1292271432#37" type="string">User</value>
</add-attr>
</add>
</input>
</nds>

The single most important thing you need to know about XPATH in Identity
Manager is the what the current context is currently set too. When you
look at web based examples they start showing you XPATH that starts at
the very beginning of the XML document, and you start trying that
approach, so starting with an XPATH of nds/input/add/@src-dn to try and
select the XML Attribute src-dn in the <add> event node, but it does not
work.

When you test it in the XPATH builder in Designer, you might or might
not get it to work, and these two issues are basically the same. The
XPATH builder in Designer is generic and handles XPATH the way it
generically can be handled. However, IDM starts its current context for
XPATH at the event or operation node. That is the <add>, <modify>,
<delete>, <query>, and <instance> nodes. (There are more event
documents types, but you get the idea.)

To get the Designer XPATH tool to work right, you need to select the
correct current context in the left hand side on the XML source
document. You can read about this in more detail in the article:
http://www.novell.com/communities/no...d-context-node

Once you know that simple fact many things get easier.

Thus in the example I used above, to select the src-dn XML attribute
from the <add> node, you could just use the XPATH of:
@src-dn (Would return \ACME-IDV\acme\Users\Applications\listuser )

Similarly, some common XML attributes you might want to pick out of the
document.
@dest-dn (Would return \ACME-IDV\acme\Users\Applications\listuser )
@event-id (Would return osg900lnx#20101213201759#1#1 )
@cached-time (Would return 20101213201759 )
@qualified-src-dn (Would return
O=acme\OU=Users\OU=Applications\CN=listuser )

If you need to test them in a condition block, there is actually a
DirXML Script token, If XML attribute, and you can test for available,
equal, and their opposites. No need to even consider XPATH in this case.

That is another key thing to know about XPATH. Are you selecting? Or
testing for true or false? Or are you doing math? These are different
approaches and can be similar or different depending on the circumstances.

Selecting will usually take the node you have specified and down the
tree, assuming you have somewhere to store it (like a local variable set
to type nodeset) that is appropriate. Where as testing will return
true if there are any values at all, and false if nothing matches the
test. Performing functions (which can actually be string manipulation
or numeric math) looks different as well.

You could easily select any particular attribute value with an XPATH of
something like:

add-attr[@attr-name="Login Disabled"]/value

which would return false. You might want to add a /text() at the end to
be sure to cast it as a string, but not really needed.

For fun, you could select all nodes that have a syntax type of say,
string, with the following XPATH.
add-attr[value/@type="string"]

That says, all <add-attr> nodes, whose <value> subnode, has the XML
attribute type set to string.

It also turns out a lot of the built in DirXML Script tokens can be
replicated in XPATH. In fact it was probably the other way around,
where many common tasks that were being done very often in XPATH were
bundled into built in functionality.

The first example to work through are the four Attribute tokens.

Source Attribute
Destination Attribute
Operational Attribute
Attribute.

Source Attribute reads from the source system, depending on the channel
it is called in, that is either eDirectory (when called on the
Subscriber channel) or the connected system (when called on the
Publisher channel).

This performs a query, and the XPATH to do it would look something like
this:
query:readObject($srcQueryProcessor, association, @src-dn, @class-name,
'CN')/attr/value

This uses the Java query function that Novell provides as part of IDM.
It tries to find the user by the association value, for the attribute CN.

Destination Attribute is much the same as Source Attribute it just looks
in the other direction. That would be the connected system on the
Subscriber channel, and eDirectory if called on the Publisher channel.

query:readObject($destQueryProcessor, association, @dest-dn,
@class-name, 'CN')/attr/value

This makes a call to the destQueryProcessor instead of the
srcQueryProcessor that is defined by default by the engine.

Next up is Operational Attribute which looks at the current event
document and pulls the value out of the document. This is a little
trickier as it could be an <add> a <modify>, or an <instance> event and
the way the values are represented in the XDS document as slightly
different. The XPATH would be:

((add-attr|attr)[@attr-name = 'CN']) | (modify-attr[@attr-name =
'CN']/add-value))

This looks for an <add-attr> (from an <add> event) or an <attr> node
(from an <instance> document), using the pipe (|) symbol for OR, where
the XML attribute in that node attr-name is CN. (The square brackets
are predicates and let you specify conditions on the node you are trying
to match. Then there is another OR symbol because it might also a
<modify> event, where it the node we want would be under a <modify-attr>
value with the same predicate of @attr-name='CN' and then an <add-value>
node under the <modify-attr>.

You can see this getting a little bit complex and that the Operational
attribute token is quite a bit easier than doing it in XPATH. But wait,
there's more!

The Attribute token is a pretty darn cool one, since it can use the
current documents value (the operational attribute) and if not found,
fall back to check the source, and query for the source attribute. Even
better, it will also read out of the cache, that persists for the
duration of the rule. You may not have noticed but the engine will look
ahead in your policy and if it sees that you are going to query on the
same object for different attributes it will combine them into a single
query event, which is way more efficient than say three separate queries
for different attributes on the same object.

The data it reads out is cached for the duration of the Policy object,
and the Attribute token will read from that cache, making it even more
efficient.

To do this in XPATH, you actually loose the benefit of that caching and
read ahead querying, alas. But the XPATH is pretty cool, since it is
really a combination of the Operational attribute XPATH and Source
Attribute XPATH leading us too:

(((add-attr|attr)[@attr-name = 'CN']) | (modify-attr[@attr-name =
'CN']/add-value)) | query:readObject($srcQueryProcessor, association,
@src-dn, @class-name, 'CN')/attr/value)

That's easy to read right? Well it is if you realize if is just the two
XPATH statements for Operational Attribute and Source Attribute combined
inside a pair of round brackets with a pipe between them.

I have written up some much more complex examples, like doing Schema
Mapping in XPATH, and Mapping tables in XPATH, and you can read about
those approaches here:
http://www.novell.com/communities/no...a-mapping-rule
http://www.novell.com/communities/no...duce-map-token
http://www.novell.com/communities/no...entity-manager

The next thing worth discussing is the notion of functions in XPATH.
There are a number of functions available, and the RFC is the reference
for finding those functions. There are some common string functions
like string-length(), substring-before(), substring() that will let you
chop up a string as needed.

An example might be substring-before('geoffc@acme,com','@') to get the
first part of an email address.

There are some functions that cast values, like number() and string()
that force the data to be of the specified format as best is possible.

You can do the various numeric operations you would expect with
addition, subtraction, multiplication, division (integer and floating
point), and the greater/less than operators.

There is a cool function called count() that will count the number of
nodes that the value in the brackets contains. For example
count(attr[@attr-name='CN'] would return the number of <attr
attr-name='CN'> nodes. If this returns 0, then that could be treated as
a boolean false in a true/false test.

Next up is the use of variables. You can reference local variables
(both driver scoped and policy scoped) as well as Global Configuration
Variables (GCV) using the $VarName notation. Use a dollar sign to
indicate this is a variable. Do recall that variable replacement
elsewhere in DirXML Script is a leading AND trailing $ sign, so do not
get confused, it is very easy! You can also use the ~GCVName~ notation
in XPATH, but it will be replaced at driver start with a literal string,
so you might need to surround that in quotation marks if the context
requires it.

Thus you could set local variable (type nodeset) TEST to Query for the
'DirXML-Associations' values for an object. You would get back a
slightly complicated multi valued attribute that might look something
like this:

You could use a for-each loop over that local variable, and then inside
the loop the current-node local variable will be the current node you
are looping through.

Since the context is still the <instance> node, if more than one object
is being returned, you would have multiple <instance> documents, so you
would loop through those first, where the current-node would be the
<instance> node. Then using another for-each loop, you could loop over
the local variable
$current-node/attr[@attr-name='DirXML-Associations']/value to loop
through all the various values.

Now DirXML-Associations is fun as it is a structured attribute with
three components, which you might want to select or test with. So that
would mean inside this inner loop, where the current node context is the
<value> nodes, of which there will be many, one per driver the object is
associated with, you could test if XPATH true
$current-node/component[@name='volume']=$dirxml.auto.driverdn to utilize
one of the built in GCVs.

Where things get really complicated is when you combine a couple of
predicates and steps along the way. I find it easier to break it up
into pieces to try to understand what each piece is doing, one step at a
time.

One confusing thing is that you could have a fairly complex XPATH like:
$DriverConfig/definitions/group[@name="GroupName]/definition[@name='SomeGCV']/value/item[3]

Where there are multiple predicates. I am suggesting a list GCV, inside
a GCV group (this is immaterial unless you like to make pretty GCV
layouts) that has three different predicates along the way.

I want to look in the DriverConfig local variable, (pretend I read back
the drivers DirXML-ConfigValues attribute, base 64 decoded it, and XML
Parsed it) and then there is a <definitions> node, and then look for the
<group> node that has the XML attribute name of GroupName, and then
under that, find the <definition> node, whose XML attribute name is
SomeGCV, and since this is a list GCV, it have a <value> node, with the
third <item> node. The predicate [3] is really shorthand for
[position()=3] which is sort of a weird notation to me, but whatever
works. By taking it apart, it is much easier to understand.

As always (like in LDAP filter) breaking up the enclosing brackets will
help break it into smaller chunks to understand as well. So our example
for Attribute above of:
(((add-attr|attr)[@attr-name = 'CN']) | (modify-attr[@attr-name =
'CN']/add-value)) | query:readObject($srcQueryProcessor, association,
@src-dn, @class-name, 'CN')/attr/value)

Could be broken up as:
(
(
(add-attr|attr)[@attr-name = 'CN'])
| (modify-attr[@attr-name = 'CN']/add-value)
)
| query:readObject($srcQueryProcessor, association, @src-dn,
@class-name, 'CN')/attr/value
)

Hmm, that makes more sense to me. You have the add-attr|attr in one
test, then OR the modify-attr, and all that is bracket enclosed so it is
all those three options OR the query call. Not sure how well that works
displayed.

I have been trying when I work on other articles and come across an
interesting or complex XPATH to try and take it apart to explain it
better, so keep reading my articles to find out more XPATH examples.