Join and Split tokens in Identity Manager 3.5 and higher

Join and Split tokens in Identity Manager 3.5 and higher:

Novell Identity Manager has gone through a number of versions, and with each version new features get added. In the original release, when it was still called DirXML 1.0 the only real option was XSLT. With the release of Nsure Identity Manager 2.0 we got DirXML Script. This is probably one of the nicest features of Identity Manager.

DirXML Script the language, and Policy Builder the interface to build rules in DirXML Script, are very powerful. With each release, new tokens or actions get added, usually to resolve a pressing need or else to simplify a common task.

For example, you can read about the Time and Convert Time tokens, (Using the Time Tokens in IDM 3.5) which was basically a wrapper around the Java time function. But it is so much easier than doing it the old way. The Map token and Mapping Table objects (Mapping tables and Render browsed DN relative to policy option) are great additions to our toolset. The Query token (The Query token in Identity Manager) is another great one.

Sometimes the change is relatively subtle but powerful, as in the case of enhancements to the Find Matching object token New IDM 3.6 enhancement to do-find-matching-object

Sometimes the change is the ability to use an entirely new language, like the addition of support for ECMA Script in Identity Manager 3.5. This was a really big deal, as it allows you to write things in ECMA Script (The more correct name for the latest versions of JavaScript. which never had anything to do with Java anyway) and as Google has shown with its Google Web Toolkit, and others (JQuery, Yahoos toolkit, etc) there is amazing power in ECMA Script!

To try and collate some of the possibilities, that are useful at least in an Identity Manager context, I have an article that highlights a long list of possible functions.
Open Call for useful ECMA functions to use in Identity Manager

If you have any others to add, please let me know, and I will update the article with your submission.

Once you get used to all the new tokens, it often is hard to go back to the old ways! This bothered me so much, when I had to revisit a client using Identity Manager 3.01 and I had been working with 3,5 and 3.6 since then, that I decided to write an article about some of the main missing features, and how to work around then,
Working in IDM 3.0.1 after using 3.5.1

I still have to address the most important new token in Identity Manager 3.5, the nested IF token. The ability to easily nest an IF THEN ELSE test inside a rule, is a real game changer between the approach you have to take in Identity Manager 3.01 and 3.5 and higher. But that is a topic for another article I think.

For today's article, I want to talk about another new pair of tokens that are quite interesting and worth talking about the Join and Split tokens. They are somewhat complimentary, in
that you can take a node set and join it, and then take the results and split them.

The split token is useful if you have a string, that has some kind of delimiter, say a comma or a colon. A great example of this is structured attributes, when looked at via LDAP. Whether that is via the LDAP driver, and a query token, or via an ECMA Script call to an LDAP function. Lothar Haegers (
IDM 3.5 Password Notification Service Driver
) Password Notification driver is a great example of the latter case. In it, he has an ECMA Script LDAP Search function. It returns results in a node set, and structured attributes are returned with pound (#) signs between the fields.

Thus for attributes like DirXML-Association or ACL, both of which uses Path syntax, after you query via either approach (into a local variable QUERY-RESULT), you could set a local variable, say QUERY-VALUE by selecting your node with XPATH, say $QUERY-RESULT/attr[@attr-name="ACL"] or $QUERY-RESULT/attr[@attr-name="DirXML-Associations"] and then use the split token on the QUERY-VALUE local variable, splitting along the # sign boundary.

The Split token is similar to the Map token, in that by itself it does nothing. You need to nest something that holds the value to be split, underneath it. This can be confusing at first glance. In XML it is very obvious once you see it written out, as the 'thing' (could be a local variable, a Global Configuration Variable, a Source Attribute token, whatever) to be split, needs to be added as children nodes under the token-split node.

<do-set-local-variable name="SPLIT-NODESET" scope="policy">
<token-split delimiter="#">
<token-local-variable name="QUERY-VALUE"/>

Once you have done it once in Argument Builder it is pretty obvious, but the first time, like with the Map token it is not very clear what to do next.

Note that the results are a node set, so you will need to make sure to specify the local variable you store the results in is a node set or else it will not work well at all. What will happen if you do not store it in a node set variable, is that it will get 'flattened' and probably look like the values of each node concatenated together with no delimiter. I suppose that would be a funny approach to removing delimiters from a string, but it seems like a real workaround, when there are much simpler ways to do it.

Once you have the node set, you can do with it as you please. One difference between a structured attribute being returned by a Query against eDirectory is that you do not have the <component> nodes inside the <value> node, so you cannot use the usual XPATH approach of value/component[name="something"] to select the part you want, but it is however ordered.

Thus the first piece it split out is the first value on the node set and so on. You can probably select this with an XPATH of something like $QUERY-VALUE/value[0] for the first part, then $QUERY-VALUE/value[1] and so on, using positional notation.

The Split token can be very powerful, as you can see, since doing this other ways could be pretty messy. Probably a series of substring-before() functions, where the delimiter (# in our case) is the thing to substring before.

The contrasting token to Split is the obvious one, Join. Join is great, since it effectively flattens a node set, letting you specify the delimiter that separates the values.

This can be immensely useful if you have a large node set of values that you need output as a string. Perhaps even as a way of visualizing what the data in the node set is. Sometimes I find it useful for troubleshooting a rule, to email myself some debug information. Including the node set is very useful in that case. I could have used the XML Serialize token to convert the node set to a string that I can email, but sometimes i just want to see the values.

The other approach that I previously would have taken (The XML Parse and XML Serialize tokens are of the same era as the Split and Join token, all four tokens being added in Identity Manager 3.5) would have been to unroll the values in a for-each loop through the node set.

To do that I would have a node set of say QUERY-RESULT, and loop through that in a for-each token. Inside the loop, I would set a local variable, say QUERY-VALUE to itself plus a delimiter, and then the current node variable. At the end of the loop I have the same basic result, just slower.

<token-local-variable name="QUERY-RESULT"/>
<do-set-local-variable name="QUERY-VALUE" scope="policy">
<token-local-variable name="QUERY-VALUE"/>
<token-text xml:space="preserve">#</token-text>
<token-local-variable name="current-node"/>

You might want a counter as well to know how many values were found, but that is easy enough to add. A counter has one trick to it, which is how you do math in XPATH and the use of spaces. You can read more about this issue at: XPATH and math but the gist of it is, to be safe, when doing math in XPATH, you should use the number() function.

That is, set a local variable COUNTER to XPATH of number($COUNTER) 1 inside your for each loop. The other important step is you should initialize the variable before you start, as there seems to be a need to do that. Thats easy enough, just before your loop remember to set local variable COUNTER to XPATH of number(0) to be certain.

It would be nice to have a simple function to do this, but since it is available in XPATH I suppose it is not really a pressing need.

One important thing to note is the node set used depends on how you got the results into the QUERY-REULT token. See XPATH and the context node for more details on where the current context is. You might need to specify the node set for the for-each loop as XPATH of $QUERY-RESULT/attr[@attr-name="Something"]/value if you retrieved it via a Query, as opposed to retrieving it via a Source or Destination Attribute token. As always, look at trace to see what the node set looks like, in the results, before deciding.

Hope this is helpful to you, and if you have a favorite token in Identity Manager, why not write about it and share with the rest of us. I will be honest, I did not even know about these two new tokens until someone in the forum suggested using them. Once I looked at them, I was impressed! To this day, I still keep finding new uses for tokens I had not thought of or even tokens I had never even considered using.

I am sure there are interesting uses of tokens I have never thought of. Why just this past week I saw two references to using the Document token, in really interesting ways that I had never before considered. I always approached the problem the 'hard' way of reading back the attribute from the object in eDirectory (usually a configuration attribute on a driver or driver set object, like DirXML-ShimConfigInfo) then using the Base64 decode token to get it into text, and finally the XML Parse token to convert it to a node set, so I can parse out what I needed via an XPATH select statement. But it turns out you can get the entire document much more simply just using the Document token. I literally had never noticed that until this past week. So please, if there is a token you think has some interesting uses, write about it and share! You can get Cool Solutions points for the article, which you can redeem for all sorts of fun gifts and prizes at:

If you are not already aware of the Novell Support Forums, you should take a look. There is a large body of knowledge left in threaded discussion format, and often your question has been asked before. The good news is that Google does index the forums, and often searches will return forum posts.

You can access the forums via the web at in a web interface. I personally prefer to use a news reader like Thunderbird or even the GroupWise client to read the forums via NNTP at nntp://

As you can see there are lots of ways to get involved and share some knowledge, so if you enjoyed this, or any of my articles in the past, here is my fee. I expect you to write at least one article about something of interest, or post an answer in the forums. The more people that get involved the better everything gets, and it is easy, and can be fun, so why not take a swing at it?


How To-Best Practice
Comment List
  • Geoffery,

    FYI - here's an example of how to get the data out of the nodeset - you can simply use the [] notation on the token on the node-set results from the split token (as opposed to the /value[] notation mentioned above). Here's an example I did to parse a field, then put it back together again.

    I feel like I should be using join to put them back together, but I'm not sure how to do an inplace modify of the $splitCredentialFields[7] variable . .suggestions?

    Thanks for your articles once again!

    [08/17/16 18:43:21.775]:MyID ST: Action: do-set-local-variable("splitCredentialFields",scope="policy",arg-node-set(token-split("::",token-local-variable("current-node")))).
    [08/17/16 18:43:21.775]:MyID ST: arg-node-set(token-split("::",token-local-variable("current-node")))
    [08/17/16 18:43:21.775]:MyID ST: token-split("::",token-local-variable("current-node"))
    [08/17/16 18:43:21.775]:MyID ST: token-split("::",token-local-variable("current-node"))
    [08/17/16 18:43:21.775]:MyID ST: token-local-variable("current-node")
    [08/17/16 18:43:21.776]:MyID ST: Token Value: "iPad::987654321::tablet::2/12/2015 12:00:00::2/13/2015 13:34:30::2/13/2016 13:34:30::ISSUED".
    [08/17/16 18:43:21.776]:MyID ST: Arg Value: "iPad::987654321::tablet::2/12/2015 12:00:00::2/13/2015 13:34:30::2/13/2016 13:34:30::ISSUED".
    [08/17/16 18:43:21.776]:MyID ST: Token Value: {"iPad","987654321","tablet","2/12/2015 12:00:00","2/13/2015 13:34:30","2/13/2016 13:34:30","ISSUED"}.
    [08/17/16 18:43:21.777]:MyID ST: Arg Value: {"iPad","987654321","tablet","2/12/2015 12:00:00","2/13/2015 13:34:30","2/13/2016 13:34:30","ISSUED"}.
    [08/17/16 18:43:21.777]:MyID ST: Action: do-remove-src-attr-value("bocX509DCCredentialInformation",token-local-variable("current-node")).
    [08/17/16 18:43:21.777]:MyID ST: arg-string(token-local-variable("current-node"))
    [08/17/16 18:43:21.777]:MyID ST: token-local-variable("current-node")
    [08/17/16 18:43:21.777]:MyID ST: Token Value: "iPad::987654321::tablet::2/12/2015 12:00:00::2/13/2015 13:34:30::2/13/2016 13:34:30::ISSUED".
    [08/17/16 18:43:21.778]:MyID ST: Arg Value: "iPad::987654321::tablet::2/12/2015 12:00:00::2/13/2015 13:34:30::2/13/2016 13:34:30::ISSUED".
    [08/17/16 18:43:21.778]:MyID ST: Action: do-add-src-attr-value("bocX509DCCredentialInformation",token-xpath("$splitCredentialFields[1]")+"::"+token-xpath("$splitCredentialFields[2]")+"::"+token-xpath("$splitCredentialFields[3]")+"::"+token-xpath("$splitCredentialFields[4]")+"::"+token-xpath("$splitCredentialFields[5]")+"::"+token-xpath("$splitCredentialFields[6]")+"::REVOKED").
    [08/17/16 18:43:21.779]:MyID ST: arg-string(token-xpath("$splitCredentialFields[1]")+"::"+token-xpath("$splitCredentialFields[2]")+"::"+token-xpath("$splitCredentialFields[3]")+"::"+token-xpath("$splitCredentialFields[4]")+"::"+token-xpath("$splitCredentialFields[5]")+"::"+token-xpath("$splitCredentialFields[6]")+"::REVOKED")
    [08/17/16 18:43:21.779]:MyID ST: token-xpath("$splitCredentialFields[1]")
    [08/17/16 18:43:21.779]:MyID ST: Token Value: "iPad".
    [08/17/16 18:43:21.780]:MyID ST: token-text("::")
    [08/17/16 18:43:21.780]:MyID ST: token-xpath("$splitCredentialFields[2]")
    [08/17/16 18:43:21.780]:MyID ST: Token Value: "987654321".
    [08/17/16 18:43:21.780]:MyID ST: token-text("::")
    [08/17/16 18:43:21.780]:MyID ST: token-xpath("$splitCredentialFields[3]")
    [08/17/16 18:43:21.780]:MyID ST: Token Value: "tablet".
    [08/17/16 18:43:21.780]:MyID ST: token-text("::")
    [08/17/16 18:43:21.781]:MyID ST: token-xpath("$splitCredentialFields[4]")
    [08/17/16 18:43:21.781]:MyID ST: Token Value: "2/12/2015 12:00:00".
    [08/17/16 18:43:21.781]:MyID ST: token-text("::")
    [08/17/16 18:43:21.781]:MyID ST: token-xpath("$splitCredentialFields[5]")
    [08/17/16 18:43:21.781]:MyID ST: Token Value: "2/13/2015 13:34:30".
    [08/17/16 18:43:21.781]:MyID ST: token-text("::")
    [08/17/16 18:43:21.781]:MyID ST: token-xpath("$splitCredentialFields[6]")
    [08/17/16 18:43:21.782]:MyID ST: Token Value: "2/13/2016 13:34:30".
    [08/17/16 18:43:21.782]:MyID ST: token-text("::REVOKED")
    [08/17/16 18:43:21.782]:MyID ST: Arg Value: "iPad::987654321::tablet::2/12/2015 12:00:00::2/13/2015 13:34:30::2/13/2016 13:34:30::REVOKED".