Xquery-如何匹配量词表达式中的两个序列

Xquery-如何匹配量词表达式中的两个序列,xquery,contains,Xquery,Contains,和许多人一样,我正在处理基于XML的Mondial数据库。如果XQuery语法没有尽力破坏,那将是小菜一碟 let $inland := //province/@id where every $sea in //sea satisfies $sea/located/@province != $inland return $inland 我试图在上面做的是找到所有的“内陆”省份,没有的省份旁边都有大海。但是,这不起作用,因为$sea/located/province是一个很大的字符串,它与每个省

和许多人一样,我正在处理基于XML的Mondial数据库。如果XQuery语法没有尽力破坏,那将是小菜一碟

let $inland := //province/@id
where every $sea in //sea satisfies
$sea/located/@province != $inland
return $inland
我试图在上面做的是找到所有的“内陆”省份,没有的省份旁边都有大海。但是,这不起作用,因为$sea/located/province是一个很大的字符串,它与每个省份都有边界

所以我试着修改成

let $inland := //province/@id
where every $sea in //sea satisfies
not(contains($sea/located/@province, $inland))
return $inland
在那里我只想找到属于海洋边缘省份的省份。简单明了

错误消息:

Stopped at C:/Users/saffekaffe/Desktop/mondial/xml/country_without_island.xml, 2/1:
[XPTY0004] Item expected, sequence found: (attribute id {"prov-Greece-2"},....
我该怎么做

//sea/所在地/省份示例@

province="prov-France-5 prov-France-20 prov-France-89 prov-France-99" 
//province/@id示例

id="prov-Greece-2"

XQuery有多种不同于您预期的工作方式

  • 比较运算符
    =
    =具有存在语义。这意味着
    $seq1=$seq2
    相当于
    某些$seq1中的$x,$seq2中的$y满足$x=$y
    。查询
    ('foo','bar')=('bar','baz','quoz')
    返回
    true
    ,因为至少有一个公共项

  • 类似于
    //province/@id
    的XQuery异常计算为所有匹配节点的序列。在您的情况下,这将是一个超过1000个省id的序列:
    (id=“prov-cid-cia-greese-2”,id=“prov-cid-cia-greese-3”,id=“prov-cid-cia-greese-4”,[…])
    。然后将此序列绑定到
    let
    子句中的变量
    $inland
    。由于您不迭代
    $INLAIN
    中的单个项目(例如,使用
    for
    子句),因此
    where
    条件将立即对全球所有省份的整个序列起作用。所以你的条件
    在//sea中每$sea满足
    $sea/位于/@省!=$内陆现在的意思是:
    “对于每个
    sea
    都有一个
    位于其旁边,其
    @id
    至少不等于所有现有省id中的一个。”
    这将返回
    false
    ,因为有
    sea
    s没有
    子对象,例如亚丁湾

  • contains($str,$sub)
    不适合检查子字符串是否包含在空格分隔的字符串中,因为它还匹配部分条目:
    contains(“foobar baz qux”,“oob”)
    返回
    true

    相反,您应该使用
    tokenize($str)
    将字符串拆分为多个部分并查看其各个部分,或者使用
    contains token($str,$token)

  • 综上所述,与原始查询非常相似的正确查询是:

    for $inland in //province/@id
    where
      every $sea in //sea
      satisfies not(contains-token($sea/located/@province, $inland))
    return $inland
    
    另一种方法是首先收集
    sea
    s旁边的所有(唯一)省份,然后返回不按该顺序排列的所有省份:

    let $next-to-sea := distinct-values(//sea/located/@province/tokenize(.))
    return //province/@id[not(. = $next-to-sea)]
    
    更紧凑(但可能效率更低):

    另一方面,您可以使用XQuery 3.0地图,通过一次查找来替代所有海滨省份的潜在线性搜索:

    let $seaside :=
      map:merge(
        for $id in //sea/located/@province/tokenize(.)
        return map{ $id: () }
      )
    return //province/@id[not(map:contains($seaside, .))]
    

    不确定这是您当前的错误,但XQuery必须返回格式良好的XML,而格式良好的XML序列不是(没有根标记);请尝试
    return{$inland}
    maybe?它在contains函数中的逗号处特别出错。谢谢你的建议。对,contains是一个字符串函数,它需要一个字符串和一个潜在的子字符串,而不是一个序列和一个潜在的元素。应该会有帮助。我知道他们在那里做了什么@Aaron,但这还不够,我需要能够与一个子串匹配,例如一个名为“province2”的省和一个与“province2 province4”接壤的海洋。非常感谢!这同时回答了很多问题,很好的信息:)
    let $seaside :=
      map:merge(
        for $id in //sea/located/@province/tokenize(.)
        return map{ $id: () }
      )
    return //province/@id[not(map:contains($seaside, .))]