Idomatic way of expressing equality in XPath 2.0

If $ A and $ B are sequences, what is the idiomatically preferred way to test $ A and $ B for established equality? I know that existential semantic behavior ($A = $B) makes this expression not an answer. The semantics of ordering deep-equal() also forbids me to use this.

My impulse is to use:

 ((every $a in $A satisfies $a = $B) and (every $b in $B satisfies $b = $A)) 

I found surprisingly little about equality checking with Google (more precisely, I didn’t find anything), and I didn’t see it mentioned in @ Michael- Kay Chapter 8, 9, 10 or 13. It’s hard to believe that I was the first XPath user to come across with this necessity. This makes me wonder if I am asking the wrong question.

+7
source share
2 answers

Firstly, it depends on how you evaluate the equality between the elements, for example, do you compare two elements using "=", "is", "eq" or "deep-equal"? Your own answer tells you what you think of "=", which is almost the same as "eq" when applied to elements, except that it has slightly different conversion rules. And, as it happens, this is not a good operator to use with sets, because it is not transitive: untypedAtomic ("4") = 4, untypedAtomic ("4") = "4", but not (4 = "4") . Therefore, suppose that “eq” is transitive, except in angular cases involving numerical rounding of values ​​that are “almost equal”.

Then I would be inclined to suggest (as others did)

 deep-equal(sort($A), sort($B)) 

except that some data types (e.g. QNames) have a specific equality operator, but the order is not defined. Thus, this will work for integers and strings, but not for QNames.

Obviously, the O (n ^ 2) method is provided in your “impulse” solution, but is there any better way?

What about

 let $A := count(distinct-values($a)) let $B := count(distinct-values($b)) let $AB := count(distinct-values(($a, $b)) return $A = $AB and $B = $AB 

It should be O (n log n).

+2
source share

An interesting and well-asked question! In my opinion, using every and satisfies to overcome the existential properties of sequence comparison is a very efficient and fairly canonical method.

But since you are asking about another approach: how about sorting sequences before comparing them with deep-equal() ? Assume the two sequences in the following stylesheet:

 <?xml version="1.0" encoding="UTF-8" ?> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="text"/> <xsl:variable name="A" select="('a','b','c')"/> <xsl:variable name="B" select="('a','c','b')"/> <xsl:template match="/"> <xsl:choose> <xsl:when test="deep-equal($A,$B)"> <xsl:text>DEEP-EQUAL!</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>NOT DEEP-EQUAL</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:transform> 

And of course, this conversion returns

 NOT DEEP-EQUAL 

But if you sort the sequences before comparing them, for example, with a custom function using xsl:perform-sort , see the corresponding part of the specification :

 <?xml version="1.0" encoding="UTF-8" ?> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:local="www.local.com" extension-element-prefixes="local" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:output method="text"/> <xsl:variable name="A" select="('a','b','c')"/> <xsl:variable name="B" select="('a','c','b')"/> <xsl:template match="/"> <xsl:choose> <xsl:when test="deep-equal(local:sort($A),local:sort($B))"> <xsl:text>DEEP-EQUAL!</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>NOT DEEP-EQUAL</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:function name="local:sort" as="xs:anyAtomicType*"> <xsl:param name="in" as="xs:anyAtomicType*"/> <xsl:perform-sort select="$in"> <xsl:sort select="."/> </xsl:perform-sort> </xsl:function> </xsl:transform> 

then the result will be

 DEEP-EQUAL! 

EDIT : actually establishing equality will mean that not only the order doesn't matter, but the duplicates shouldn't matter either. Therefore, correct uniform equality will also mean applying distinct-values() to sequence variables:

 <xsl:when test="deep-equal(local:sort(distinct-values($A)),local:sort(distinct-values($B)))"> 
+3
source share

All Articles