如何确认一个字符串序列是另一个字符串序列的子集?

How do I confirm that one string sequence is a subset of another?

我不知道如何确定一组字符串 (xs:string*) 是否是一组参考字符串的子集。

我假设节点集操作适用于 xs:string*,但它们适用于类型 node(),而不适用于 xs:string。我也尝试了更简单的 contains() 函数,它只适用于单个字符串,不适用于字符串序列。

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="permitted" select="tokenize('1,2,3,278', ',')"/>

    <xsl:template match="/">
    <html>
        <xsl:apply-templates/>
    </html>

<xsl:template match="experience">
    <xsl:variable name="test" select="tokenize(ids, ', ')"/>

<xsl:if test="count($permitted | $test)=count($permitted)">
        <xsl:copy-of select="."/> 
    </xsl:if>

</xsl:template>

</xsl:stylesheet>

我明白了:

错误:文档顺序排序器所需的项目类型是 node();提供的值具有项目类型 xs:string

如果您使用(XPath 2 及更高版本)every $s in $test satisfies $s = $permitted,那么我认为您的检查应该适用于像字符串这样的原子值序列。

替代方案:count($test) = count($test[. = $permitted])

使用:

not($vTest[not(. = $vPermitted)])

基于 XSLT 的验证:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:variable name="vPermitted" as="xs:string*" select="'1', '2', '3', '278'"/>

  <xsl:variable name="vTest1" as="xs:string*" select="'1', '2', '3'"/>
  <xsl:variable name="vTest2" as="xs:string*" select="'1', '2', '3', '4'"/>

  <xsl:template match="/">
    <xsl:sequence select="not($vTest1[not(. = $vPermitted)])"/>
    <xsl:sequence select="not($vTest2[not(. = $vPermitted)])"/>
  </xsl:template>
</xsl:stylesheet>

当上述转换应用于任何 XML 文档(未使用)时,将评估两个 XPath 表达式并输出它们正确的、想要的结果:

true false

注意

即使在没有序列概念的 XPath 1.0 (XSLT 1.0) 中也可以使用完全相同的表达式,但可以使用节点集代替。


解释:

这是“Principle of Double Negation”。这个原理被认为是经典逻辑中的一个思维规律。罗素和怀特海在《数学原理》中将该原理表述为命题逻辑定理:

"This is the principle of double negation, i.e. a proposition is equivalent of the falsehood of its negation."


最佳实施 -- 接近 O(N)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:variable name="vPermitted" as="map(xs:string, xs:boolean)" select=
    "map{'1' : true(), '2' : true(), '3' : true(), '278' : true()}"/>

  <xsl:variable name="vTest1" as="xs:string*" select="'1', '2', '3'"/>
  <xsl:variable name="vTest2" as="xs:string*" select="'1', '2', '3', '4'"/>

  <xsl:template match="/">
    <xsl:sequence select="not($vTest1[not($vPermitted(.))])"/>
    <xsl:sequence select="not($vTest2[not($vPermitted(.))])"/>
  </xsl:template>
</xsl:stylesheet>

当上述转换应用于任何 XML 文档(未使用)时,将评估两个 XPath 表达式并输出它们正确的、想要的结果:

true false

虽然前面的表达式(包括当前接受的答案中的表达式)都有时间复杂度O(M*N),但上面的XPath 3.1 expression uses a pre-populated (global / created only once) map所以任何检查如果一个键存在需要常数时间——因此这个算法的总时间复杂度是O(N)

这里我们做出合理的假设,即正在使用的 XPath 引擎具有经过良好优化的地图实现,例如基于哈希表的地图实现

集合操作不适用于字符串,但序列操作可以。您的尝试:

<xsl:if test="count($permitted | $test)=count($permitted)">

可以重写为:

<xsl:if test="deep-equal(distinct-values(($permitted, $test)), $permitted)">