XPath Filter Dialect: Examples
The product team and I just wrapped up our week at the TechReady event in Seattle. Bobby presented an excellent session on codeless provisioning, focusing on configuration and tips and tricks, and I presented a session on workflow and activity extensibility in ILM "2". We also had the opportunity to solicit feedback about the product from attendees. This event reminded me of just how new so many of the concepts in ILM “2” are, and how much more knowledge there is which can be shared. My last post on the XPath Filter Dialect addressed one area where we frequently get questions, as our use of the xpath language is so pervasive throughout the product.
While many of the common questions and areas of concern are fresh in my memory, I’ll proceed to share some guidance where I can.
Let’s start with some examples that demonstrate the use of the XPath Filter Dialect addressing common queries (for reporting and other scenarios). I’d recommend first reading the previous post on the xpath fundamentals.
Note: The XPath Filter Dialect is case sensitive. Keep this in mind when writing your xpath filters. For example, /Person[displayname = ‘value’] is NOT the same as /Person[DisplayName = ‘value’].
Example 1: A User’s Pending Approvals
You’ll need the following xpath if you want to build a report or page that lists all the approvals that are pending a response from a specific user.
Let’s assume the user, for which you want to see the pending approvals, has an Account Name of ‘mmeyers’ and an ObjectID of ‘11111111-1111-1111-1111-111111111111’.
This first filter demonstrates how to identify the pending approvals based on the user’s ObjectID:
/Approval[ApprovalStatus = ‘Pending’ and Approver = ‘11111111-1111-1111-1111-111111111111’]
This second filter demonstrates how to identify the pending approvals based on the user’s Account Name:
/Approval[ApprovalStatus = ‘Pending’ and Approver = /Person[AccountName = ‘mmeyers’]]
Notice that in the second example we make use of a location path expression, /Person[AccountName = ‘mmeyers’], inside the predicate in order to identify approvals where the Approver is a user with the specified Account Name.
Note that the ApprovalStatus represents the status of an approval and can have one of the following values:
A status of ‘Pending’ means the approval is currently awaiting a response from one of the users listed in the Approvers attribute of the approval.
A status of ‘Approved’ means the Request associated with the approval has been approved by the required number of approvers. After an approval has been created it will only be marked as ‘Approved’ if the minimum number of responses, as specified by the ApprovalThreshold attribute of the approval, is met.
A status of ‘Rejected’ means a user designated as an approver for the approval have rejected the approval. At any point in time if a valid approver rejects an approval, that approval is immediately rejected and the workflow and associated Request is terminated.
A status of ‘Expired’ means the approval has reached the time indicated by the ApprovalDuration attribute on the Approval object as no response to the approval has been submitted.
Example 2: All Security Groups expiring within the next 7 days.
/Group[Type= ‘Security’ and ExpirationTime <= op:add-dayTimeDuration-to-dateTime(fn:current-dateTime(), xs:dayTimeDuration(\"P7D\"))]
Example 3: All Orphaned Security Groups
An ‘orphaned’ security group here refers to a group with no owner. The following is the xpath to identify such groups:
/Group[Type = ‘Security’ and Owner != /Person]
Example 4: People who are members of both the "Interns" group and the "Full Time Employees" group:
While my example here may not be a very compelling one, the goal is to demonstrate how we can identify users that are in sets or groups producing conflicting roles or permissions.
/Person[ObjectID = /Group[DisplayName = ‘Interns’]/ComputedMember and ObjectID = /Group[DisplayName = ‘Full Time Employees’]/ComputedMember ]
Note that I used the DisplayName attribute to identify the groups of interest, but the better practice would be to use a unique identifier to identify the groups, such as their ObjectID attribute.
Example 5: People who were EVER members of both the "Interns" group and the "Full Time Employees" group at the same time:
The previous example identified people who are currently members of two conflicting groups. The following example identifies people who were ever members of these conflicting groups at the same time. This example makes use of the historical querying feature of ILM to scope the query to a time in the past.
allTime(/Person[ObjectID = /Group[DisplayName = ‘Interns’]/ComputedMember and ObjectID = /Group[DisplayName = ‘Full Time Employees’]/ComputedMember ])
Example 6: All permissions that Kim Abercombie had in the month of January, 2009.
Again, here we see the use of historical query to check for a condition that was met at some time in the past. This time we are checking for permissions that existed for a user between a specified time period.
betweenTime(/ManagementPolicyRule[GrantRight = 'True' and PrincipalSet = /Set[ComputedMember = /Person[ DisplayName = ‘Kim Ambercrombie’]]] , ‘2009-01-01T00:00’, ‘2009-01-31T00:00’)
Notice that the filter above is looking for any Management Policy Rule, of the type that grants permissions, which granted permissions to a set that contained Kim Ambercrombie in its membership
Example 7: Changes to security groups in the last 10 days
/Request[Target = /Group[Type = 'Security'] and Operation = 'Put' and CreatedTime >= op:subtract-dayTimeDuration-from-dateTime(fn:current-dateTime(), xs:dayTimeDuration('P10D'))]
The above filter is returning all Requests that were created, within the last 10 days, to modify a security group. If you want to find only the Requests that were actually ‘completed’, or the ones that were ‘rejected’ or still pending, simply add an additional condition based on the status of the request.
Example 8: All full time employees that were ever contractors (ie. transitioned from one job to another).
/Person[EmployeeType=’Full Time Employee’ and ObjectId = allTime(/Person[EmployeeType=’Contractor’])]
Each of these examples is related to a question I've recieved in the past. As more common scenarios become apparent, I will post examples addressing them.