2012-05-17 207 views
0

我是xquery的新手。我有以下XML文檔:Xquery遍歷樹

<?xml version="1.0" encoding="UTF-8"?> 
    <lines> 
     <line> 
      <id>1</id> 
      <par>1</par> 
     </line> 
     <line> 
      <id>2</id> 
      <par>1</par> 
     </line> 
     <line> 
      <id>3</id> 
      <par>2</par> 
     </line> 
     <line> 
      <id>4</id> 
      <par>2</par> 
     </line> 
     <line> 
      <id>5</id> 
      <par>1</par> 
     </line> 
     <line> 
      <id>6</id> 
      <par>5</par> 
     </line> 
     <line> 
      <id>7</id> 
      <par>5</par> 
     </line> 
     <line> 
      <id>8</id> 
      <par>5</par> 
     </line> 
    </lines> 

我想創建一個能夠獲得作爲輸入某個ID的功能,並且將返回所有行元素 - 這個ID的後裔,其中包括作爲輸入的一個。例如給出1作爲輸入,它將返回帶有1,2,3,4,5,6,7,8的線元素。我知道我可以使用以下方法進入深度1:lines/line[par=id_given],但是如果我想要獲取所有後代,該怎麼辦?

回答

0

你必須定義一個遞歸遍歷樹的函數。這一次確實工作水平明智:

declare function local:traverse($tree as element(lines), $id as xs:integer*) as element(line)* { 
let $level := $tree//line[par=$id][id!=$id] 
return 
    if ($level) 
    then ($level, local:traverse($tree, $level/id)) 
    else() 
}; 

可以使用local:traverse(/lines, 0)調用它。

但是這個函數不會處理你的示例XML,因爲這不是樹:在根元素中有一個循環是不允許的。你將不得不引入一些新的唯一root ID,或者從根目錄中刪除父項以獲得真正的樹。

<lines> 
    <line> 
     <id>1</id> 
     <par>0</par> 
    </line> 
    [snip] 

你也可以改變上面的代碼,以便能夠處理這些自引用:謂語[id!=$id]加入的$level定義的結束,這將排除自我引用。現在您的根節點被排除在結果之外,將其重新包括在函數調用中:(/lines/line[id=1], local:traverse(/lines, 1))

+0

該ID僅用於該示例的目的,因此第二個選項無效。我的情況下的par元素表示父節點。所以給一個id我想獲得所有的節點。例如,對於輸入1,我想獲得輸入2的所有節點,我希望得到2,3,4和輸入5 - > 5,6,7,8 – ntheo

+0

對不起,錯過了你的問題。我重新定義了我的答案。 –