Исключить пустые списки из пересечения в XQuery - PullRequest
1 голос
/ 09 января 2012

У меня есть несколько списков, которые могут быть или не быть пустыми.Я хочу найти те элементы, которые встречаются во всех списках, но только для тех списков, которые не являются пустыми.У меня есть что-то вроде этого:

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

Но если какой-либо из списков пуст, это выражение возвращает пустой список.Можно ли каким-то образом исключить список из моего пересечения, если он пустой?

РЕШЕНИЕ: Это решение, которое я выбрал, основано на ответе, предоставленном Раноном.

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 ]

1 голос
/ 09 января 2012

Вместо непосредственного использования встроенного 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)
      )
    )
...
0 голосов
/ 09 января 2012
* +1000 * Используйте
       ( $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)] )

при оценке этого выражения XQuery (с использованием Saxon 9.3.04 EE) в следующем XML-документе:

 <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>
0 голосов
/ 09 января 2012

Вы можете проверить все списки, если они пусты. Если это так, присвойте им объединение всех списков.

Для моего примера я использовал functx-реализацию intersect и union, чтобы тоже иметь возможность пересекать последовательности. Возможно, следует написать какую-то функцию, чтобы избежать избыточного кода, но для демонстрации идеи этот код подходит:

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), но это приведет к двойным элементам, что приведет к более медленным операциям пересечения для большого числа элементов.

...