[xquery-talk] distance between elements and hierarchical order

Sergio Andreozzi sergio.andreozzi at cnaf.infn.it
Fri Dec 9 19:48:19 PST 2005

Hi David,

David Carlisle wrote:
>>I build a sequences with their QName 

> why sequences of names rather than the elements themselves?
> especially if you then compare with eq as that means you can't tell one
> element from another. It only works in the example you gave as all your
> element names were distinct. If your doc had nested elements with teh
> same name, and you wanted to compare
> doc("test.xml")/A/A[2]/A/A[3] and doc("test.xml")/A/A[5]/A[2]/A[1] then
> your sequences will each be a sequence of "A" with no indication of
> which element it is naming, and every item in the sequnce will compare
> true with eq against every other item, so  
> where $x-name eq $y-names[$x-pos]
> isn't going to test anything as it will always be true().

your solution works perfectly for the earlier problem, that is
measuring the distance between two elements in an XML document. With
this definition and your example, dist(/A/A[2]/A/A[3],
/A/A[5]/A[2]/A[1])=7 and that is right.

In my last email, I was introducing a different problem, which solution
is inspired by the previous posts. I understand that it was not so
clear. I try to better describe it: given two path expressions in the
form of ("/" QName)+, what would be the distance between two distinct
elements identified by them if their respective ancestors considered in
pairs when equal for their QName and level position are also equal in
their identities?

I've refined the solution based on your example, as I found out a
problem when the nodes identified by the path expression have the same

let $x := doc("test2.xml")/A/A[2]/A/A[3],
     $y := doc("test2.xml")/A/A[5]/A[2]/A[1]

let $x-names := $x/ancestor-or-self::element()/name(),
     $y-names := $y/ancestor-or-self::element()/name()

return count($x-names) + count($y-names) + 1 - 2*count(
   		for $x-name at $x-pos in $x-names
   	 	where $x-name eq $y-names[$x-pos]  	 	
              	return 1) + ( if (( count($x-names) eq count($y-names))
              	     and $x/name() eq $y/name() ) then 2 else 0)

shortest-possible-dist(/A/A[2]/A/A[3], /A/A[5]/A[2]/A[1]) = 3
shortest-possible-dist(/A/A[2]/A/A[1], /A/A[2]/A/A[3])    = 3
shortest-possible-dist(/A/A[1], /A/A[5]/A[2]/A[1])        = 3

Regards, Sergio

More information about the talk mailing list