【问题标题】:Xquery traverse treeXquery 遍历树
【发布时间】:2012-05-17 20:19:52
【问题描述】:

我是 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],但是如果我想获取所有后代怎么办?

【问题讨论】:

    标签: xquery traversal


    【解决方案1】:

    你必须定义一个递归遍历树的函数。这个确实可以按级别工作:

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

    【讨论】:

    • ID 仅用于示例,因此第二个选项无效。在我的例子中,par 元素代表父节点。所以给定一个 id 我想得到下面的所有节点。例如对于输入 1,我想获取输入 2 的所有节点,我想获取 2,3,4 和输入 5 ->5,6,7,8
    • 抱歉,误解了您的问题。我重新定义了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多