XPath导航以XML编码的图结构

我有一个用XML编码的类似图的结构。精确地说,是有向无环图。节点是唯一标识的,并具有编码的前后关系。

是否可以构造一个XQuery或XPath函数,该函数可以在图形中导航以找到满足简单条件的第一个节点?

更准确地说,让我们看下面的XML文档:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <obj>
        <id>1</id>
        <name>FINDME</name>
        <relations>
            <successor>2</successor>
        </relations>
    </obj>
    <obj>
        <id>2</id>
        <relations>
            <predecessor>1</predecessor>
            <successor>3</successor>
        </relations>
    </obj>
    <obj>
        <id>3</id>
        <relations>
            <predecessor>2</predecessor> 
        </relations>
    </obj>
</doc>

假设当前节点为3。我想找到前任节点的ID,它的名称标签等于“ FINDME”。为此,我可以使用以下XPath:

/doc/obj[name='FINDME'
      and id=/doc/obj[
          id=/doc/obj[
               id=3
               ]/relations/predecessor
           ]/relations/predecessor
       ]/id

是否可以泛化查询以处理任意级别的关系?


编辑:joemfb答案确实回答了这个问题。我还有一个额外的请求,它可以为一个节点处理一个以上的前任对象,并返回不超过一次的任何节点吗?

因此,它也适用于以下示例:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <obj>
        <id>1</id>
        <name>FINDME</name>
        <relations>
            <successor>2</successor>
            <successor>4</successor>
        </relations>
    </obj>
    <obj>
        <id>4</id>
        <relations>
            <successor>2</successor>
            <predecessor>1</predecessor>
        </relations>
    </obj>
    <obj>
        <id>2</id>
        <relations>
            <predecessor>1</predecessor>
            <predecessor>4</predecessor>
            <successor>3</successor>
        </relations>
    </obj>
    <obj>
        <id>3</id>
        <relations>
            <predecessor>2</predecessor> 
        </relations>
    </obj>
</doc>
joemfb

如果我正确理解您的要求,那么您希望找到前任者,只要它们存在。这是递归函数的完美应用。

这是一个XQuery解决方案:

xquery version "1.0";

declare function local:predecessors($doc, $node)
{
  let $immediate-predecessor := $doc/doc/obj[id = $node/relations/predecessor]
  return
    if (fn:exists($immediate-predecessor))
    then (
      $immediate-predecessor,
      local:predecessors($doc, $immediate-predecessor)
    )
    else ()
};

let $doc := document { (: your doc ... :) }
let $results := local:predecessors($doc, $doc/doc/obj[id eq "3"])
return element results { $results intersect $results }

更新

为了支持多个predecessor元素,谓词[id = $node/relations/predecessor]需要通用比较运算符=,该运算符支持任一操作数中的序列,而不是值比较运算符eq

要返回不同的节点,我们可以使用intersectoperator,该操作符返回两个操作数共有的唯一节点序列(我也可以使用union类似的方法返回唯一节点)。

我已经在Saxon HE中测试了这些更改:

java -cp /usr/local/Cellar/saxon/9.5.1.6/libexec/saxon9he.jar \
  net.sf.saxon.Query -q:test.xq | xmllint --format -

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章