XPATH Examples

From MicroFocusInternationalWiki
Revision as of 15:11, 23 July 2008 by Descent (Talk | contribs) (Get Value From a Nodeset)

Jump to: navigation, search

This page is intent to help demystify XPATH expressions by showing example expressions with explanations as to what elements they match. Example traces are encouraged.

Reference Information

XPATH 1.0 http://www.w3.org/TR/xpath

XPATH 2.0 http://www.w3.org/TR/xpath20
Note that xpath 2.0 is not supported by Novell Identity Manager as of Version 3.5

Geoff Carman's XPATH Article http://www.novell.com/communities/node/4833/some-thoughts-xpath-novell-identity-manager

Examples

Strip Empty Values [Add]

This rule removes elements that have either an empty value [value="] or do not have a value defined [not(*)]

<rule>
  <description>Strip Empty Values [Add]</description>
  <conditions>
    <and>
      <if-operation mode="case" op="equal">add</if-operation>
    </and>
  </conditions>
  <actions>
    <do-strip-xpath expression="add-attr[value="]"/>
    <do-strip-xpath expression="add-attr[not(*)]"/>
  </actions>
</rule>

When the above rule is applied to this input document:

<input>
  <add class-name="User" qualified-src-dn="o=dirXML Test\ou=Users\cn=User1" src-dn="o=dirXML Test\ou=Users\cn=User1">
    <association>o=dirXML Test\ou=Users\cn=User1</association>
    <add-attr attr-name="cn">
      <value>User1</value>
    </add-attr>
    <add-attr attr-name="Surname">
      <value></value>
    </add-attr>
    <add-attr attr-name="Given Name"/>
  </add>
</input>

The result is:

<input>
  <add class-name="User" qualified-src-dn="o=dirXML Test\ou=Users\cn=User1" src-dn="o=dirXML Test\ou=Users\cn=User1">
    <association>o=dirXML Test\ou=Users\cn=User1</association>
    <add-attr attr-name="cn">
      <value>User1</value>
    </add-attr>
  </add>
</input>

The expression value=" matches the <value></value> and the expression not(*) matches the Given Name example above

Strip Empty Values [Modify]

This is similar to the above rule, but looks for elements that are modify values as opposed to add values.

<rule>
  <description>Strip Empty Values [Modify]</description>
  <conditions>
    <or>
      <if-operation mode="case" op="equal">modify</if-operation>
      <if-operation mode="case" op="equal">sync</if-operation>
    </or>
  </conditions>
  <actions>
    <do-strip-xpath expression="modify-attr/add-value[value=]"/>
    <do-strip-xpath expression="modify-attr[not(*)]"/>
  </actions>
</rule>

Example Document that would have the value stripped:

<modify-attr attr-name="Surname">
  <add-value>
    <value></value>
  </add-value>
</modify-attr>

OR

<modify-attr attr-name="Surname"/>

Strip 'Remove All Values'

This removes the instance of <remove-all-values/> from an attribute named Surname

<do-strip-xpath expression="*[@attr-name='Surname']/remove-all-values"/>

If the above rule was applied to this document:

<modify-attr attr-name="Surname">
  <remove-all-values/>
  <add-value>
    <value>Last Name1</value>
  </add-value>
</modify-attr>

The result would be:

<modify-attr attr-name="Surname">
  <add-value>
    <value>Last Name1</value>
  </add-value>
</modify-attr>

Component Value of a Structured Attribute

This rule will grab the value of a single component of a struvtured attribute. This can be used with attributes like postal address.

<token-xpath expression="$current-node/component[@name='COMPONENT1']"/>

When applied to this example:

<modify-attr attr-name="Postal Address">
  <remove-all-values/>
  <add-value>
    <value type="structured">
      <component name="COMPONENT1">Address Name</component>
      <component name="COMPONENT2">1234 Street Address</component>
      <component name="COMPONENT3">Additional Street Address</component>
      <component name="COMPONENT4">City</component>
      <component name="COMPONENT5">State</component>
      <component name="COMPONENT6">84000</component>
    </value>
  </add-value>						
</modify-attr>

The value Address Name would be returned.

Detect a Warning Error

This expression detects a warning returned on the driver.

<if-xpath op="true">self::status[@level = 'warning']</if-xpath>

For example:

<input>
  <status event-id="777" level="warning">Operation vetoed by unassociated object.</status>
</input>

The subsequent rule:

<token-xpath expression="self::status"/>

Would return "Operation vetoed by unassociated object."

Detect a Merge Event

<conditions>
  <and>
    <if-operation op="equal">modify</if-operation>
    <if-xpath op="true">@from-merge = 'true'</if-xpath>
  </and>
</conditions>

Retrieve a Portion of a String

This example grabs just the last portion of a string delimited by a hyphen

<actions>
  <do-set-local-variable name="vSSN" scope="policy">
    <arg-node-set>
      <token-split delimiter="-">
        <token-local-variable name="current-node"/>
      </token-split>
    </arg-node-set>
  </do-set-local-variable>
  <do-set-dest-attr-value name="vLAST4">
    <arg-value>
      <token-xpath expression="$vSSN[3]"/>
    </arg-value>
  </do-set-dest-attr-value>
</actions>

When applied to the value 333-22-4444 this would return just 4444

Strip a Specific Value of a Specific Attribute

<do-strip-xpath expression="*[@attr-name='CN']/add-value[value='Common Name']"/>

Removes this Value of Common Name:

<add-attr attr-name="cn">
  <value>Common Name</value>
</add-attr>

Which Returns:

<add-attr attr-name="cn"/>

You should then follow with the strip empty values rules above to clean this up.

Remove Un-Associated Group Memberships

You want to remove values of an attribute that do not contain a particular XML attribute

Input Document

	<input>
		<modify class-name="User" qualified-src-dn="o=dirXML Test\ou=Users\cn=User1">
			<association>o=dirXML Test\ou=Users\cn=User1</association>
			<modify-attr attr-name="Surname">
				<remove-all-values/>
				<add-value>
					<value>Last Name1</value>
				</add-value>
			</modify-attr>
			<modify-attr attr-name="Given Name">
				<remove-all-values/>
				<add-value>
					<value>First Name1</value>
				</add-value>
			</modify-attr>
			<modify-attr attr-name="Group Membership">
				<add-value>
					<value association-ref="cn=groupname,o=myorg" type="dn">\Tree1\myorg\groupname</value>
					<value type="dn">\Tree1\myorg\anothergroup</value>
					<value association-ref="cn=yetonemore" type="dn">\Tree1\myorg\yetonemore</value>
				</add-value>
			</modify-attr>
		</modify>
	</input>

Policy

	<rule>
		<description>Strip Unassociated Memberships</description>
		<conditions>
			<and>
				<if-op-attr name="Group Membership" op="available"/>
			</and>
		</conditions>
		<actions>
			<do-strip-xpath expression="*[@attr-name='Group Membership']/add-value/value[not(@association-ref)]"/>
		</actions>
	</rule>

Output Result

	<input>
		<modify class-name="User" qualified-src-dn="o=dirXML Test\ou=Users\cn=User1">
			<association>o=dirXML Test\ou=Users\cn=User1</association>
			<modify-attr attr-name="Surname">
				<remove-all-values/>
				<add-value>
					<value>Last Name1</value>
				</add-value>
			</modify-attr>
			<modify-attr attr-name="Given Name">
				<remove-all-values/>
				<add-value>
					<value>First Name1</value>
				</add-value>
			</modify-attr>
			<modify-attr attr-name="Group Membership">
				<add-value>
					<value association-ref="cn=groupname,o=myorg" type="dn">\Tree1\myorg\groupname</value>
					<value association-ref="cn=yetonemore" type="dn">\Tree1\myorg\yetonemore</value>
				</add-value>
			</modify-attr>
		</modify>
	</input>


Query Vault for DN using Email address as a matching attribute

<rule>
	<description>Query Manager DN</description>
	<conditions>
		<and>
			<if-attr name="directSupervisorEmail" op="available"/>
		</and>
	</conditions>
	<actions>
		<do-set-local-variable name="DEST-DN" scope="policy">
			<arg-string>
				<token-text xml:space="preserve">rackspace\users\active</token-text>
			</arg-string>
		</do-set-local-variable>
		<do-set-local-variable name="SEARCH-VALUE" scope="policy">
			<arg-string>
				<token-attr name="directSupervisorEmail"/>
			</arg-string>
		</do-set-local-variable>
		<do-set-local-variable name="ManagerDN" scope="policy">
			<arg-node-set>
				<token-xpath expression="query:search($destQueryProcessor,
					'subtree',,$DEST-DN,,'Internet Email  Address',$SEARCH-VALUE,)"/>
			</arg-node-set>
		</do-set-local-variable>
		<do-set-local-variable name="SRC-DN" scope="policy">
			<arg-string>
				<token-xpath expression="$ManagerDN/@src-dn"/>
			</arg-string>
		</do-set-local-variable>
	</actions>
</rule>
<rule>
	<description>Display Direct Supervisor Query Result</description>
	<conditions>
		<and>
			<if-local-variable name="SRC-DN" op="available"/>
		</and>
	</conditions>
	<actions>
		<do-set-local-variable name="lvarManagerDN" scope="policy">
			<arg-string>
				<token-parse-dn dest-dn-format="src-dn" start="0">
					<token-local-variable name="SRC-DN"/>
				</token-parse-dn>
			</arg-string>
		</do-set-local-variable>
		<do-set-dest-attr-value name="manager">
			<arg-value>
				<token-local-variable name="lvarManagerDN"/>
			</arg-value>
		</do-set-dest-attr-value>
	</actions>
</rule>

Run external code on the IDM engine server

Windows only ;-)

<rule>
	<description>Start Notepad</description>
	<conditions/>
	<actions>
		<do-set-local-variable name="Runtime">
			<arg-object>
				<token-xpath expression="java.lang.Runtime:getRuntime()"/>
			</arg-object>
		</do-set-local-variable>
		<do-set-local-variable name="Notepad">
			<arg-object>
				<token-xpath expression="java.lang.Runtime:exec($Runtime, 'notepad.exe c:\NewDoc.txt')"/>
			</arg-object>
		</do-set-local-variable>
		<do-set-local-variable name="Returncode">
			<arg-string>
				<token-xpath expression="java.lang.Process:waitFor($Notepad)"/>
			</arg-string>
		</do-set-local-variable>
		<do-set-local-variable name="Returncode">
			<arg-string>
				<token-xpath expression="java.lang.Process:exitValue($Notepad)"/>
			</arg-string>
		</do-set-local-variable>
	</actions>
</rule>

(with IDM versions earlier than 3.5 you need to define namespace for the java classes)

Remove an attribute of an element

From: Father Ramon \ Forums

This expression will strip an attribute of a value.

To remove the "type" attribute of the value below:

<attr attr-name="memberOf">
     <value naming="true" type="dn">CN=dept,OU=groups,DC=domain,DC=com</value>
</attr>

Apply this expression:

<do-strip-xpath expression="*[@attr-name="memberOf"]//value/@type"/>

Which would return this:

<attr attr-name="memberOf">
     <value naming="true">CN=dept,OU=groups,DC=domain,DC=com</value>
</attr>

This could also be accomplished without XPATH as below:

<do-reformat-op-attr name="memberOf">
     <arg-value type="string">
          <token-local-variable name="current-value"/>
     </arg-value>
</do-reformat-op-attr>

From Father Ramon:

Reformat actually replaces all the existing values for the attributes with new ones. In that sense it is much more broad than the XPath approach because it actually throws away the original value elements and replaces it with a newly fabricated one that will only have on it exactly what you specify to put on it.

Get Value From a Nodeset

A query noun token returns its values in type nodeset. One way to get a specific value is to set a local variable using the query token and then use an xpath expression to return the desired value.

<token-xpath expression="$MyLocalVar//value[1]/text()"/>

Allow Unsynchronized Values to Exist

When an attribute is synchronized, you usually designate one system as authoritative. However, their could be instances where you want both to be authoritative. For example:

  • Identity Vault Values
    • Today
    • Tomorrow
  • Destination System Values
    • Yesterday
<rule>
	<description>Merge Description Values</description>
	<comment xml:space="preserve">This rule will take any description values being sync'd and convert
	   them to add value events instead of synchronization to preserve destination values.</comment>
	<conditions>
		<and>
			<if-op-attr name="Description" op="available"/>
		</and>
	</conditions>
	<actions>
		<do-set-local-variable name="lvDescription" scope="policy">
			<arg-node-set>
				<token-op-attr name="Description"/>
			</arg-node-set>
		</do-set-local-variable>
		<do-set-local-variable name="lvDescriptionRemove" scope="policy">
			<arg-node-set>
				<token-xpath expression="*[@attr-name='Description']/remove-value/value"/>
			</arg-node-set>
		</do-set-local-variable>
		<do-strip-op-attr name="Description"/>
		<do-for-each>
			<arg-node-set>
				<token-local-variable name="lvDescriptionRemove"/>
			</arg-node-set>
			<arg-actions>
				<do-remove-dest-attr-value name="Description">
					<arg-value>
						<token-local-variable name="current-node"/>
					</arg-value>
				</do-remove-dest-attr-value>
			</arg-actions>
		</do-for-each>
		<do-for-each>
			<arg-node-set>
				<token-local-variable name="lvDescription"/>
			</arg-node-set>
			<arg-actions>
				<do-add-dest-attr-value name="Description">
					<arg-value>
						<token-local-variable name="current-node"/>
					</arg-value>
				</do-add-dest-attr-value>
			</arg-actions>
		</do-for-each>
	</actions>
</rule>

Resultant Values:

    • Today
    • Tomorrow
    • Yesterday

Furthermore, removing a value that only exists in the vault, will simply remove that value in the destination.