如果我正確理解你的XML,所有的圖形基本上的步驟,如果沒有一步可以省略,每一個步驟可能有幾個備選序列。 (因此,通過圖的路徑集本質上是各種替代方案的笛卡爾乘積。)如果不是這樣,那麼接下來的將不會是你想要的。
獲得笛卡爾產品的最簡單方法是在笛卡爾乘積中爲每個因子使用一個for
子句的XQuery FLWOR表達式,如Jens Erat的初始答案所示。
如果您事先不知道會有多少因素(因爲您不知道圖表中可能會出現什麼樣的「類型」值序列),並且不希望重新制定查詢那麼最簡單的事情就是編寫一個遞歸函數,它將一系列「類型」值作爲一個參數,並將您正在處理的「根」元素作爲另一個參數,並且一次處理一個因子。
這個函數做這項工作,爲您的樣品輸入:
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's solution to a related problem借用,我們可以由此計算的「類型」值的適當的序列:
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
謝謝@Mikael。這個解決方案是否保證了基於'Type'屬性的元素順序? – ARZ 2013-04-25 05:02:39
@ARZ我這麼認爲,但正如你在C. M. Sperberg-McQueen的回答中所看到的那樣,當使用'distinct-values'時,順序不能保證。我將發佈一個更新,其中我不使用'distinct-values'並利用一個(或兩個)表變量來代替更「SQL」的答案。 – 2013-04-25 05:11:03