0

i am new to xquery. I have the following xml document :

<?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>

I would like to create a function that would get as input a certain id , and would return all the line elements - descendants of this id , including the one given as input. For example giving as input 1 it would return the line elements with ids 1,2,3,4,5,6,7,8. I know i can go to depth 1 using the following: lines/line[par=id_given], but what if i would like to fetch all descendants?

4

1 回答 1

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,因为这不是树:根元素中有一个不允许的循环。您将不得不引入一些新的唯一根 id 或从根中删除父级以获得真正的树。

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

您还可以更改上面的代码以处理这些自引用:将谓词添加[id!=$id]到定义的末尾$level,这将排除自引用。现在您的根节点已从结果中排除,将其重新包含在函数调用中:(/lines/line[id=1], local:traverse(/lines, 1))

于 2012-05-17T20:35:53.687 回答