在 XPath 2.0 中表达集合相等性的惯用方式
Idiomatic way to express set equality in XPath 2.0
如果 $A 和 $B 是序列,那么测试 $A 和 $B 的集合相等性的惯用首选方法是什么?我知道 ($A = $B)
的存在语义行为使这个表达式 不是 的答案。 deep-equal()
的排序语义也禁止我使用它。
我的冲动是用:
((every $a in $A satisfies $a = $B) and (every $b in $B satisfies $b = $A))
关于通过 Google 进行的集合相等性测试,我发现的很少(准确地说,我什么也没发现),而且我没有在 @Michael-Kay 中看到它第 8、9、10 或 13 章。很难相信我是第一个遇到这种需求的 XPath 用户。这让我想知道我是否问错了问题。
一个有趣且问得很好的问题!在我看来,使用every
和satisfies
来克服序列比较的存在性是一种非常有效且足够规范的方法。
但是既然你问的是另一种方法:在将序列与 deep-equal()
进行比较之前对序列进行排序怎么样?让我们假设以下样式表中的两个序列:
<?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>
当然还有这种转变returns
NOT DEEP-EQUAL
但是如果您在比较序列之前对它们进行排序,例如使用使用 xsl:perform-sort
的自定义函数,请参阅 relevant 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>
那么,结果就是
DEEP-EQUAL!
EDIT:事实上,set equality 意味着不仅顺序无关紧要,而且重复也不应该产生影响。因此,适当的集合相等性意味着也将 distinct-values()
应用于序列变量:
<xsl:when test="deep-equal(local:sort(distinct-values($A)),local:sort(distinct-values($B)))">
首先,这取决于您如何评估项目之间的相等性,例如,您是使用“=”、"is"、"eq" 还是 "deep-equal" 来比较两个项目?您自己的回答表明您正在考虑“=”,它在应用于项目时几乎与 "eq" 相同,只是它的转换规则略有不同。碰巧的是,它不是与集合一起使用的好运算符,因为它不是可传递的:untypedAtomic("4") = 4,untypedAtomic("4") = "4",但不是 (4 = "4")。因此,让我们假设 "eq",它是传递性的,除非涉及 "almost equal".
值的数字舍入的极端情况
然后我会倾向于建议(就像其他人所做的那样)
deep-equal(sort($A), sort($B))
除了一些数据类型(例如 QNames)定义了相等运算符,但没有定义顺序。所以这适用于整数和字符串,但不适用于 QName。
显然您的 "impulse" 解决方案中给出了 O(n^2) 方法,但是可以做得更好吗?
怎么样
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
这应该是 O(n log n)。
如果 $A 和 $B 是序列,那么测试 $A 和 $B 的集合相等性的惯用首选方法是什么?我知道 ($A = $B)
的存在语义行为使这个表达式 不是 的答案。 deep-equal()
的排序语义也禁止我使用它。
我的冲动是用:
((every $a in $A satisfies $a = $B) and (every $b in $B satisfies $b = $A))
关于通过 Google 进行的集合相等性测试,我发现的很少(准确地说,我什么也没发现),而且我没有在 @Michael-Kay 中看到它第 8、9、10 或 13 章。很难相信我是第一个遇到这种需求的 XPath 用户。这让我想知道我是否问错了问题。
一个有趣且问得很好的问题!在我看来,使用every
和satisfies
来克服序列比较的存在性是一种非常有效且足够规范的方法。
但是既然你问的是另一种方法:在将序列与 deep-equal()
进行比较之前对序列进行排序怎么样?让我们假设以下样式表中的两个序列:
<?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>
当然还有这种转变returns
NOT DEEP-EQUAL
但是如果您在比较序列之前对它们进行排序,例如使用使用 xsl:perform-sort
的自定义函数,请参阅 relevant 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>
那么,结果就是
DEEP-EQUAL!
EDIT:事实上,set equality 意味着不仅顺序无关紧要,而且重复也不应该产生影响。因此,适当的集合相等性意味着也将 distinct-values()
应用于序列变量:
<xsl:when test="deep-equal(local:sort(distinct-values($A)),local:sort(distinct-values($B)))">
首先,这取决于您如何评估项目之间的相等性,例如,您是使用“=”、"is"、"eq" 还是 "deep-equal" 来比较两个项目?您自己的回答表明您正在考虑“=”,它在应用于项目时几乎与 "eq" 相同,只是它的转换规则略有不同。碰巧的是,它不是与集合一起使用的好运算符,因为它不是可传递的:untypedAtomic("4") = 4,untypedAtomic("4") = "4",但不是 (4 = "4")。因此,让我们假设 "eq",它是传递性的,除非涉及 "almost equal".
值的数字舍入的极端情况然后我会倾向于建议(就像其他人所做的那样)
deep-equal(sort($A), sort($B))
除了一些数据类型(例如 QNames)定义了相等运算符,但没有定义顺序。所以这适用于整数和字符串,但不适用于 QName。
显然您的 "impulse" 解决方案中给出了 O(n^2) 方法,但是可以做得更好吗?
怎么样
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
这应该是 O(n log n)。