2017-07-18 97 views
1

我有这样的DTD:的XPath递归定义

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

所以线程将有一个消息,这个消息可以有一个节点“回复”,那么这个节点可以包含消息,并依此类推,直到结构的底部。

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

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

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

对于每个线程我试着算儿童信息节点的数量,但这种方法计算的线程的所有子节点的数量,因此包括回复节点。

我对这种问题感到迷茫,因为我无法弄清楚在这些'递归情况下'要做什么。

+0

那么您可以访问哪个版本的XPath? 2.0,3.0,3.1? –

回答

0

假设XPath 3.0可以使用例如

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

找到线程(S)与大多数邮件的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(S)最长链嵌套答复。

对于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 

为第一个。

+0

非常感谢您的答案,我正在使用XPath 3.0!他们工作! – Pagli

+0

你好,我需要最后一件事!要找到具有最长嵌套回复链的线程,它可以简单地找到线程中回复计数的最大值,如下所示:'count(/ Root/Thread // Replies)' 这样我们也可以计算第一个答复,但我想这不重要,因为我们将有嵌套答复的数量加上第一个答复,为每个线程。 – Pagli

+0

问题是'count(/ Root/Thread // Replies)'表达式在深度和树的宽度上统计了所有的'Replies'后代,所以我不会将它看作是确定最大嵌套。 –