带有递归定义的XPath

时间:2017-07-18 17:44:20

标签: xml xpath dtd

我有这样的DTD:

     <!ELEMENT Root (Thread*) >
     <!ELEMENT Thread(ThreadId, Message) >
    <!ELEMENT Replies(message+) >
     <!ELEMENT message(timestamp, sender, recipient, subject, text, Replies?)>

因此,一个线程将有一条消息,并且此消息可以有一个节点&#39;回复&#39;,然后该节点可以包含消息等,直到结构的底部。

现在我想要做的是首先检索具有最多消息的线程的ID,然后检索具有最长嵌套回复链的线程的ID。

这感觉就像一个递归问题,但我无法在XPath中接近它。到目前为止,我尝试过这样的事情:

      For $thread in //thread
      Count(descendant-or-self::$thread/message) 

对于每个线程,我尝试计算子消息节点的数量,但此解决方案计算线程的所有子节点的数量,因此包括回复节点。

我对这类问题感到迷茫,因为我无法弄清楚在这些“递归”情况下应该做些什么。

1 个答案:

答案 0 :(得分:0)

假设XPath 3.0可以使用例如

let $max := max(/Root/Thread/count(.//Message))
return /Root/Thread[count(.//Message) eq $max]/ThreadId

找到包含大多数消息的线程的id(s),我认为

let $max := max(/Root/Thread/Message//Replies[not(Message/Replies)]/count(ancestor::Replies))
return /Root/Thread[Message//Replies[not(Message/Replies)]/count(ancestor::Replies) = $max]/ThreadId

找到具有最长嵌套回复链的线程的id。

使用XPath 2.0,您不必拥有let个表达式,因此您必须将我的样本中绑定的代码内联到引用变量的位置的变量。

在XPath 3.1中,你有一个sort函数(https://www.w3.org/TR/xpath-functions-31/#func-sort),所以不是计算最大值而是选择具有最大值的项目,你可以排序并取最后一个。

sort(/Root/Thread, (), function($t) { max($t/Message//Replies[not(Message/Replies)]/count(ancestor::Replies)) })[last()]/ThreadId

用于第二个更复杂的查询或

sort(/Root/Thread, (), function($t) { count($t//Message) })[last()]/ThreadId

第一个。