从XQuery中的交集排除空列表

时间:2012-01-08 23:09:44

标签: xquery

我有几个列表,可能是空的也可能不是。我想找到所有列表中出现的那些元素,但仅限于那些非空的列表。 我有这样的事情:

let $results := 
    $list1 intersect  
    $list2 intersect 
    $list3 intersect 
    $list4

但是如果任何列表为空,则该表达式返回一个空列表。如果它是空的,我有什么办法可以从我的交叉点中排除一个列表吗?

解: 这是我最终使用的解决方案,基于Ranon提供的答案。

let $union := $list1 | $list2 | $list3 | $list4
let $results :=
    (if ($list1) then $list1 else $union)  intersect
    (if ($list2) then $list2 else $union)  intersect
    (if ($list3) then $list3 else $union)  intersect
    (if ($list4) then $list4 else $union)

我要感谢所有贡献者。来自面向对象和程序背景,并且XQuery是一种功能性语言,它对我来说并不是那么自然(还)。

3 个答案:

答案 0 :(得分:1)

您可以将其包装在函数中并检查输入列表,而不是直接使用内置intersect

declare function local:safe-intersect($xs, $ys) {
  if(exists($xs) and exists($ys))
  then $xs intersect $ys
  else ($xs, $ys) (: at least one is empty :)
};

然后你的例子看起来像这样:

let $results := 
    local:safe-intersect(
      $list1,
      local:safe-intersect(
        $list2,
        local:safe-intersect($list3, $list4)
      )
    )
...

答案 1 :(得分:0)

如果所有列表都是空的,您可以查看它们。如果是,请为其分配所有列表的并集。

对于我的例子,我使用了intersect和union的functx实现也能够交叉序列。也许应该编写一些函数来避免冗余代码,但为了表明这个代码很好的想法:

import module namespace functx = "http://www.functx.com"  at ".../functx-1.0-nodoc-2007-01.xq";

let $list1 := (1,2,3)
let $list2 := (1,3)
let $list3 := ()
let $union := functx:value-union($list1, functx:value-union($list2, $list3))
let $list1a := if (count($list1) != 0) then $list1 else $union
let $list2a := if (count($list2) != 0) then $list2 else $union
let $list3a := if (count($list3) != 0) then $list3 else $union
return functx:value-intersect($list1a, functx:value-intersect($list2a, $list3a))

$union也可以写成($list1, $list2, $list3),但这会导致双元素导致较大元素计数的交叉操作较慢。

答案 2 :(得分:0)

使用

       ( $vL1 |   ($vL2 | $vL3 | $vL4)[not($vL1)] )
  intersect
       ( $vL2 |   ($vL3 | $vL4 | $vL1)[not($vL2)] )
  intersect
       ( $vL3 |   ($vL4 | $vL1 | $vL2)[not($vL3)] )
 intersect
      ( $vL4 |   ($vL1 | $vL2 | $vL3)[not($vL4)] )

在此表达式中,intersect的每个参数都是$vN,或者如果$vN为空,则它是其余集合的并集。

这可以更紧凑地编写为

let $vUniverse := $vL1 | $vL2 | $vL3 | $vL4
  return
            ( $vL1 |   $vUniverse [not($vL1)] )
      intersect
            ( $vL2 |   $vUniverse [not($vL2)] )
      intersect
            ( $vL3 |   $vUniverse [not($vL3)] )
     intersect
            ( $vL4 |   $vUniverse [not($vL4)] )

以下是完整示例

let $vL1 := /*/*[. mod 2 eq 1],
    $vL2 := /*/*[. mod 3 eq 1],
    $vL3 := /*/*[. mod 4 eq 1],
    $vL4 := /*/*[. mod 5 eq 1],
    $vUniverse := $vL1 | $vL2 | $vL3 | $vL4
   return
        ( $vL1 |   $vUniverse [not($vL1)] )
      intersect
        ( $vL2 |   $vUniverse [not($vL2)] )
      intersect
        ( $vL3 |   $vUniverse [not($vL3)] )
     intersect
        ( $vL4 |   $vUniverse [not($vL4)] )

在以下XML文档上评估此XQuery表达式时(使用Saxon 9.3.04 EE):

 <nums>
    <num>01</num>
    <num>02</num>
    <num>03</num>
    <num>04</num>
    <num>05</num>
    <num>06</num>
    <num>07</num>
    <num>08</num>
    <num>09</num>
    <num>10</num>
 </nums>

产生了想要的正确结果

<num>01</num>