I'm trying to make an algorithm that searchs and returns a path between two nodes in a graph in xQuery, i've had no luck so far as it returns just one node and it's adyacent nodes. First i should make clear that the graph is a directed graph and every node can have zero, one or more origins, in the XML a node only has the link to it's origin but not to it's following nodes
我正在尝试制作一个搜索并返回xQuery中图形中两个节点之间路径的算法,到目前为止它只返回一个节点和它的邻接节点。首先,我应该明确图形是有向图,并且每个节点可以有零个,一个或多个原点,在XML中,节点只有到它的原点的链接,但不是它的后续节点
Here's an example of some nodes and their XML
这是一些节点及其XML的示例
<node>
<id> 123-456-789</id>
<name> something </name>
<Links>
<Link>
<origin></origin>
</Link>
<Links>
<node>
<id> 245-678-901</id>
<name> node 2</name>
<Links>
<Link>
<origin> 123-456-789 </origin>
</Link>
<Links>
<node>
<id> xxx-xxx-xxx</id>
<name> node 3</name>
<Links>
<Link>
<origin> 123-456-789 </origin>
</Link>
<Links>
<node>
<id> 234-546-768</id>
<name> node 4</name>
<Links>
<Link>
<origin> 245-678-901</origin>
</Link>
<Links>
From that XML i would like to get the path from node 1 to node 4 ( node1-> node2 -> node4) but whatever i try to do would just give me node1-node2 and node3 but not node4 another thing is that i want to select a path that is not direct, i mean, if i want the path between node5 and node7 but both node5 and node7 are directed towards node6
从那个XML我想得到从节点1到节点4的路径(node1-> node2 - > node4),但无论我尝试做什么只会给我node1-node2和node3而不是node4另一个是我想要的东西选择一个非直接的路径,我的意思是,如果我想要node5和node7之间的路径,但node5和node7都指向node6
I've tried adapting this python code to xquery
我已经尝试将这个python代码改编为xquery
def BFS(graph,start,end,q):
temp_path = [start]
q.enqueue(temp_path)
while q.IsEmpty() == False:
tmp_path = q.dequeue()
last_node = tmp_path[len(tmp_path)-1]
print tmp_path
if last_node == end:
print "VALID_PATH : ",tmp_path
for link_node in graph[last_node]:
if link_node not in tmp_path:
new_path = []
new_path = tmp_path + [link_node]
q.enqueue(new_path)
(code not mine, it belongs to it's rightful coder at this activestate page)
(代码不是我的,它属于它在这个activestate页面的合法编码器)
here is what i've tried to do:
这是我试图做的:
declare function local:BFS($graph as element()* , $ini_node as element(Node)*, $end_node as element(Node)*) as element()*
{
let $seq := $ini_node
let $queue := ($seq)
for $item in $queue
return
if ( count($queue) > 0) then
let $seq := remove($queue, count($queue))
let $last := $seq[last()] return if (deep-equal($last, $end_node)) then $seq
else
for $node in $graph[contains(.,$graph/id[contains(.,$last/Links/Link/origin/text())])] (: what i've tried was to get the graph nodes which id is equal to the origins of the last node :)
return if(not(functx:is-node-in-sequence-deep-equal($node,$seq))) then
let $new_path:= ()
let $new_path:= insert-before($seq, count($seq)+1, $node)
let $queue := insert-before($queue,1, $new_path) return $queue
else ()
else
()
};
1 个解决方案
#1
5
The fundamental difference between XQuery and Python is that XQuery is a functional programming language. This means that the value bound to a variable cannot be modified afterwards. In your function local:BFS(...)
for example you cannot change the value of $queue
inside the loop, all you do is create a new variable $queue
that shadows the outer one.
XQuery和Python之间的根本区别在于XQuery是一种函数式编程语言。这意味着之后不能修改绑定到变量的值。在你的函数local:BFS(...)例如你不能在循环中更改$ queue的值,你要做的就是创建一个新的变量$ queue,它会遮蔽外部的变量。
In order to get it to work, you can write the outer loop as a recursive function instead that takes the current queue as an argument. Each iteration of the loop is then one invocation of the function with an updated version of the queue:
为了使其工作,您可以将外部循环编写为递归函数,而不是将当前队列作为参数。然后,循环的每次迭代都是使用更新版本的队列调用函数:
declare function local:BFS($graph, $queue, $steps, $end) {
if(empty($queue)) then error(xs:QName('local:NOTFOUND'), 'No path found.')
else (
let $curr := $queue[1], $rest-queue := $queue[position() > 1]
return (
if($curr eq $end) then local:result($steps, $end)
else (
let $successors :=
$graph//node[Links/Link/origin = $curr and not($steps/@to = id)]/id/string()
let $new-steps :=
for $succ in $successors
return <edge from="{$curr}" to="{$succ}" />
return local:BFS(
$graph,
($rest-queue, $successors),
($steps, $new-steps),
$end
)
)
)
)
};
It can be called by supplying the first edge to the start node:
可以通过向起始节点提供第一个边来调用它:
declare function local:BFS($graph, $start, $end) {
local:BFS($graph, $start, <edge to="{$start}" />, $end)
};
All used edges are stored in $steps
. In order to reconstruct the path after we found the destination, we can just traverse them backwards until we find the initial edge:
所有使用的边缘都以$步骤存储。为了在找到目的地后重建路径,我们可以向后遍历它们直到找到初始边缘:
declare function local:result($steps, $dest) {
let $pred := $steps[@to = $dest]/@from/string()
return if(exists($pred)) then (local:result($steps, $pred), $dest)
else $dest
};
If you are concerned about performance, XQuery sequences are probably not the best data structure to use as a queue. The same can be said about XML fragments for lookups. So if you have access to an XQuery 3.0 processor, you can have a look at some (at least asymptotically) more efficient data structures I wrote at https://github.com/LeoWoerteler/xq-modules. I even included Dijkstra's algorithm as an example.
如果您担心性能,XQuery序列可能不是用作队列的最佳数据结构。关于用于查找的XML片段也可以这样说。因此,如果您可以访问XQuery 3.0处理器,您可以查看我在https://github.com/LeoWoerteler/xq-modules上编写的一些(至少是渐近的)更有效的数据结构。我甚至将Dijkstra算法作为例子。
#1
5
The fundamental difference between XQuery and Python is that XQuery is a functional programming language. This means that the value bound to a variable cannot be modified afterwards. In your function local:BFS(...)
for example you cannot change the value of $queue
inside the loop, all you do is create a new variable $queue
that shadows the outer one.
XQuery和Python之间的根本区别在于XQuery是一种函数式编程语言。这意味着之后不能修改绑定到变量的值。在你的函数local:BFS(...)例如你不能在循环中更改$ queue的值,你要做的就是创建一个新的变量$ queue,它会遮蔽外部的变量。
In order to get it to work, you can write the outer loop as a recursive function instead that takes the current queue as an argument. Each iteration of the loop is then one invocation of the function with an updated version of the queue:
为了使其工作,您可以将外部循环编写为递归函数,而不是将当前队列作为参数。然后,循环的每次迭代都是使用更新版本的队列调用函数:
declare function local:BFS($graph, $queue, $steps, $end) {
if(empty($queue)) then error(xs:QName('local:NOTFOUND'), 'No path found.')
else (
let $curr := $queue[1], $rest-queue := $queue[position() > 1]
return (
if($curr eq $end) then local:result($steps, $end)
else (
let $successors :=
$graph//node[Links/Link/origin = $curr and not($steps/@to = id)]/id/string()
let $new-steps :=
for $succ in $successors
return <edge from="{$curr}" to="{$succ}" />
return local:BFS(
$graph,
($rest-queue, $successors),
($steps, $new-steps),
$end
)
)
)
)
};
It can be called by supplying the first edge to the start node:
可以通过向起始节点提供第一个边来调用它:
declare function local:BFS($graph, $start, $end) {
local:BFS($graph, $start, <edge to="{$start}" />, $end)
};
All used edges are stored in $steps
. In order to reconstruct the path after we found the destination, we can just traverse them backwards until we find the initial edge:
所有使用的边缘都以$步骤存储。为了在找到目的地后重建路径,我们可以向后遍历它们直到找到初始边缘:
declare function local:result($steps, $dest) {
let $pred := $steps[@to = $dest]/@from/string()
return if(exists($pred)) then (local:result($steps, $pred), $dest)
else $dest
};
If you are concerned about performance, XQuery sequences are probably not the best data structure to use as a queue. The same can be said about XML fragments for lookups. So if you have access to an XQuery 3.0 processor, you can have a look at some (at least asymptotically) more efficient data structures I wrote at https://github.com/LeoWoerteler/xq-modules. I even included Dijkstra's algorithm as an example.
如果您担心性能,XQuery序列可能不是用作队列的最佳数据结构。关于用于查找的XML片段也可以这样说。因此,如果您可以访问XQuery 3.0处理器,您可以查看我在https://github.com/LeoWoerteler/xq-modules上编写的一些(至少是渐近的)更有效的数据结构。我甚至将Dijkstra算法作为例子。