tags:

views:

2520

answers:

3

Hi,

I am trying to build a complex xpath expression which will answer the following condition.

From the XML data below, returns the User entity which:

  1. His loginname is "user1"
  2. His name is "User 1"
  3. He has 2 different profiles values which are "operator" and "admin" (I don't know the exact order ahead)

    <user>
      <login>user1</login>
      <name>User 1</name>
      <profile>
        <value>admin</value>
        <id>2</id>
        <description>admin users</description>
      </profile>
      <profile>
        <value>operator</value>  
        <id>1</id>
        <description>Operator</description>
      </profile>
    </user>
    
    
    <user>
      <login>user2</login>
      <name>User 2</name>
      <profile>
        <value>admin</value>
        <id>4</id>
        <description>admins users</description>
      </profile>
      <profile>
        <value>poweruser</value>  
        <id>5</id>
        <description>power users</description>
      </profile>
    </user>
    
    
    </root>
    

Can someone please supply an example for such a case?

EDIT: Added a complex profile entity

A: 

Assuming users is the root:

/users/user[login='user1' and name='User 1' 
            and (profile='admin' and profile='operator')]
dirkgently
I believe you mean "login" etc (not "@login" etc). These are elements, not attributes in the orginal XML. ;-)
Tomalak
Don't know what I was thinking :P
dirkgently
+7  A: 

The following should do what you're after:

/root/user[login='user1' and 
           name='User 1' and 
           profile='admin' and
           profile='operator']

Having two tests for the profile value might seem odd, but as there are multiple profile nodes then the condition will be satisfied as long as at least one node matches the test.

The reason you can compare profile directly to a string, even though it actually is a node is that the string-value of an element node is the string-value of all its descendants concatenated together, which in this case is just the contents of value.

If profile contained more elements than value you'd have to use a slightly more complex predicate test to determine the existence of a matching profile node based just on the value (this should work with your updated question):

/root/user[login='user1' and 
           name='User 1' and 
           profile[value='admin'] and
           profile[value='operator']]
Greg Beech
Thanks for your quick solution. May I use an XPATH like this one, or it may change the logic:/root/user[login='user1' ][ name='User 1' ][ profile[value='admin'] ][profile[value='operator']]
Interesting - I didn't know you could have multiple predicate blocks, but yes, it looks like that works too. Cool, now I have learned something as well :-)
Greg Beech
Multiple predicates only function as AND of course, the expanded syntax gives you OR too, but I prefer multiples for clarity. You could also do this with axes like preceding-sibling but that would be a bit obtuse for a simple case like this.
annakata
@Greg Beech: But you could check for duplicates this way, for example "//user[name = preceding-sibling::user/name]". Predicates can be as deeply nested as you wish.
Tomalak
The first expression seems outdated (probably the OP changed the XML after the initial solution was posted, by adding the "value" elements). The second expression is OK, but it does not check that the "user" element has *exactly* two "profile" children.
Dimitre Novatchev
@Dimitre - The question didn't ask for exactly two profile elements (or I didn't read it as such) but a simple "and count(profile)=2" could be added if that was required.
Greg Beech
A: 

Here is a more exact answer (at present Greg Beech's answer does not check for condition 3. in the problem: the user element must have exactly 2 profile children):

/*/user
        [login='user1' 
        and            
         name='User 1' 
        and  
         not(profile[3])
        and          
         profile/value='admin' 
        and           
         profile/value='operator'
         ]
Dimitre Novatchev