question

ramarb avatar image
ramarb asked ericnute edited

xpath query to find duplicate values of a node

I have a response map which has some duplicate values in it. I need to identify them, if possible, had to remove them.

Any xpath query can help me out?

 

Note: I think xpath 2.0 has 'index-of' function, which not works in iTest 3.4.2

Thanks.

iTestresponse mapxpath
10 |950

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

PreetS avatar image
PreetS answered PreetS posted

Is your response in XML?

1 comment
10 |950

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

ramarb avatar image ramarb commented ·

Yes, its XML.

0 Likes 0 ·
PaulD avatar image
PaulD answered PaulD posted

There are some tricks you can use in XPATH 1.0 to find distinct values.  I'm attaching a sample test case that shows one way to do this.  The preceding-sibling axis in XPATH is a way to get all of the preceding nodes from a given node under the same parent.

 

So, for example, if you want to get the distinct values among a list of sibling nodes, you can use an xpath query like this:

 

//elem[not(. = preceding-sibling::elem)]

 

This may look weird.  But what it is saying is, "Find each elem where its value (.) is not the same as the value of one of its previous sibling elems."  This returns a list of elem nodes, and, therefore, gets you a list of those values.

 

In the attached sample, I broaden this to dealing with a table -- where the unique values are actually in a certain column node of a repeating row node.  The principle is the same, but the query becomes slightly more complicated:

 

//row[not(name = preceding-sibling::row/name)]/name

 

This one says, "Find all of the rows, where the name in that row is not equal to the name appearing in any of the previous row nodes, then take the name from that row".

 

This is effectively equivalent to what is much simpler in XPATH 2.0:

 

distinct-values(//row/name)

 

Note that our hesitation to moving to XPATH 2.0 is that it is not backward-compatible with XPATH 1.0.  (Go figure as to why these guys who invented XPATH 2.0 made that choice!)  We want to make very sure that we will never break any test case developed with earlier versions of iTest.  If we just switch to XPATH 2.0, that could happen.  So we're being careful.


distinct.fftc (1.6 KiB)
3 comments
10 |950

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

ramarb avatar image ramarb commented ·

It works. Thanks PaulD.

 

When I modify xpath as: name //row[name = preceding-sibling::row/name]/name

I get the result as a, c, a

Whereas, I want to get duplicate nodes like 'a' and 'c' only. How to modify this query?

0 Likes 0 ·
PaulD avatar image PaulD ramarb commented ·

I'm not aware of any way to accomplish this with a single xpath query in XPATH 1.0.  However, you can do this using a bit of extra logic in your test case.  

 

First, using the technique already described, you store all of the duplicate values in a list using

 

//row[name = preceding-sibling::row/name]/name

 

and store this list in a variable, say, all_duplicates

 

Then you can do the following:

 

 

eval            set duplicates {}
foreach         possible $possible_duplicates
   if           [lsearch -exact $duplicates $possible] < 0
      then
         eval   lappend duplicates $possible
eval            puts "Distinct duplicates are: $duplicates"

 

 

The notion is that you have a list of possible duplicates, but there may be duplicates in this list.  So you create a new list called "duplicates" that will contain your final list.  Then you iterate over all of the possible duplicates.  For each of them, you check to see whether it is already in your list (in which case, the lsearch will return the index of where it appears in your list, or -1 if it is not there yet).  If it is missing, then you append this item to your list. 

 

You could, of course, put this kind of logic into a reusable procedure if you find yourself needing it more than once.  You can pass in the list to be analyzed, and get back the list of unique duplicates.

0 Likes 0 ·
ramarb avatar image ramarb PaulD commented ·

Thanks PaulD.

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.