私があなたの XML を正しく理解していれば、すべてのグラフは本質的に一連のステップであり、ステップを省略できず、各ステップにはいくつかの選択肢があります。(したがって、グラフを通るパスのセットは、基本的に、さまざまな選択肢のセットのデカルト積です。) そうでない場合、次のことはあなたが望むものではありません。
ここでデカルト積を取得する最も簡単な方法はfor
、Jens Erat の最初の回答に示されているように、デカルト積の各要素に対して 1 つの句を含む XQuery FLWOR 式を使用することです。
いくつの要素が存在するかが事前にわからない場合 (グラフで発生する可能性のある「タイプ」値のシーケンスがわからないため)、毎回クエリを新たに定式化したくない場合は、最も簡単な方法は、'Type' 値のシーケンスを 1 つの引数として取り、作業中の 'Root' 要素を別の引数として取り、一度に 1 つの要素を処理する再帰関数を作成することです。
この関数は、サンプル入力に対してその仕事をします:
declare function local:cartesian-product(
$doc as element(),
$types as xs:string*
) as xs:string* {
(: If we have no $types left, we are done.
Return the empty string. :)
if (empty($types)) then
''
(: Otherwise, take the first value off the
sequence of types and return the Cartesian
product of all Words with that type and
the Cartesian product of all the remaining
types. :)
else
let $t := $types[1],
$rest := $types[position() > 1]
for $val in $doc/Word[@Type = $t]/@Value
for $suffix in
local:cartesian-product($doc,$rest)
return concat($val, $suffix)
};
残っている唯一の問題は、ドキュメントの順序で異なる「タイプ」値のシーケンスを取得するという、少し難しい問題です。呼び出しdistinct-values($doc//Word/@Type)
て値を取得することもできますが、それらがドキュメントの順序になるという保証はありません。
関連する問題に対する Dimitre Novatchev の解決策を借りて、次のように 'Type' 値の適切なシーケンスを計算できます。
let $doc := <Root>
<Word Type="pre1" Value="A" />
<Word Type="pre1" Value="D" />
<Word Type="pre2" Value="G" />
<Word Type="pre2" Value="H" />
<Word Type="base" Value="B" />
<Word Type="post1" Value="C" />
<Word Type="post1" Value="E" />
<Word Type="post1" Value="F" />
</Root>
let $types0 := ($doc/Word/@Type),
$types := $types0[index-of($types0,.)[1]]
これは、個別の値をドキュメント順に返します。
これで、必要な結果を計算する準備が整いました。
return local:cartesian-product($doc, $types)
結果は、指定した順序とは少し異なる順序で返されます。結果の順序は気にしないと思います。
AGBC AGBE AGBF AHBC AHBE AHBF DGBC DGBE DGBF DHBC DHBE DHBF