我是xquery的新手。我有以下xml文档:
<?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它将返回带有id 1,2,3,4,5,6,7,8的线元素。我知道我可以使用以下内容进入深度1:lines/line[par=id_given]
,但是如果我想获取所有后代呢?
答案 0 :(得分: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))
。