You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XQuery函数返回值异常:仅显示部分最远国家问题排查

排查XQuery BFS函数只返回单个最远国家的问题

我明白你遇到的问题了——用BFS递归函数找尼加拉瓜的最远邻国时,本该返回加拿大、阿根廷等多个国家,结果只出了加拿大,但单独查阿根廷却正常。咱们来一步步拆解你的代码问题,然后修复它。

首先先贴出你的原始代码方便对照:

declare variable $mondial := doc("D:/mondial.xml")/mondial; 
declare variable $country := $mondial/country; 

declare function local:reachable-far($curr) { 
  if ($curr = ()) then () 
  else ( local:reachable-bfsl($curr, $curr, $curr, $curr, 0) ) 
}; 

declare function local:reachable-bfsl($queue, $seen, $lastoflevel, $currlevel, $depth) { 
  (:return current level if stack is empty (should never happen):) 
  if (empty($queue)) then (<row>{$currlevel} <depth>{$depth}</depth></row>) 
  else ( 
    let $curr := $queue[1] 
    let $neighbors-all := $curr/border/@country 
    let $neighbors-code := $neighbors-all[not(.=$seen/@car_code)] 
    let $neighbors := $country[@car_code = $neighbors-code] 
    (:if current country is not the last of level, continue with current level:) 
    return if ($curr/@car_code != $lastoflevel/@car_code) then ( 
      local:reachable-bfsl(($queue[position()>1], $neighbors), ($seen, $neighbors), $lastoflevel, $currlevel union $curr, $depth) 
    ) 
    (:if current country is the last of level:) 
    else ( 
      (:current contury has searchable neighbors or stack is not empty after popping:) 
      if (not(empty($neighbors)) or not(empty($queue[position()>1]))) then ( 
        (:clear current level, continue next level, update last of level to last in stack, depth++:) 
        local:reachable-bfsl(($queue[position()>1], $neighbors), ($seen, $neighbors), ($queue[position()>1], $neighbors)[last()], (), $depth + 1) 
      ) 
      (:current country does not have searchable neighbors and stack is empty after popping:) 
      else ( 
        <row>{trace($currlevel union $curr)} <depth>{$depth}</depth></row> 
      ) 
    ) 
  ) 
}; 

let $return-list := local:reachable-far($country[name="Nicaragua"]) 
return $return-list/country/name 

问题根源分析

你的代码核心问题出在当前层级节点的收集逻辑上:

  1. 当处理到当前层级的最后一个节点时,你把$currlevel重置成了空序列(),这导致下一层级的节点完全没有被累积。
  2. 最后返回结果时,$currlevel union $curr只能拿到最后一个被处理的节点,而不是所有同深度的最远节点——加拿大刚好是最后被处理的那个,所以只显示了它。
  3. 另外,$currlevel union $curr用union其实没必要,因为每个节点只会被处理一次,直接用序列拼接($currlevel, $curr)更合适。

修复后的代码

我调整了参数和逻辑,专门加了参数来跟踪当前层级的所有节点,以及记录所有最大深度的节点:

declare variable $mondial := doc("D:/mondial.xml")/mondial;
declare variable $country := $mondial/country;

declare function local:reachable-far($start-country) {
  // 初始化BFS:队列是起始国家,已访问集合是起始国,当前层级最后一个节点是起始国,当前层级为空,深度0,最大深度节点为空
  local:reachable-bfsl($start-country, $start-country, $start-country, (), 0, ())
};

declare function local:reachable-bfsl($queue, $visited, $last-in-level, $current-level-nodes, $current-depth, $max-depth-nodes) {
  // 队列为空时,返回所有最远的节点
  if (empty($queue)) then
    $max-depth-nodes
  else
    let $current-node := $queue[1]
    // 找到当前节点未访问过的邻国
    let $unvisited-neighbor-codes := $current-node/border/@country[not(. = $visited/@car_code)]
    let $unvisited-neighbors := $country[@car_code = $unvisited-neighbor-codes]
    // 更新已访问集合和队列
    let $updated-visited := ($visited, $unvisited-neighbors)
    let $updated-queue := ($queue[position() > 1], $unvisited-neighbors)
    // 把当前节点加入当前层级集合
    let $updated-current-level := ($current-level-nodes, $current-node)
  return
    if ($current-node/@car_code != $last-in-level/@car_code) then
      // 还没到当前层级末尾,继续处理队列,累积当前层级节点
      local:reachable-bfsl($updated-queue, $updated-visited, $last-in-level, $updated-current-level, $current-depth, $max-depth-nodes)
    else
      // 到达当前层级末尾,判断是否有下一层级
      if (not(empty($unvisited-neighbors)) or not(empty($queue[position() > 1]))) then
        // 下一层级的最后一个节点是更新后队列的最后一个元素
        let $next-last-in-level := $updated-queue[last()]
        // 更新最大深度节点:如果当前深度比之前的最大深度大,就替换成当前层级的所有节点
        let $new-max-nodes := if ($current-depth > count($max-depth-nodes) div count($country[1])) then $updated-current-level else $max-depth-nodes
        // 进入下一层级,重置当前层级集合,深度+1
        local:reachable-bfsl($updated-queue, $updated-visited, $next-last-in-level, (), $current-depth + 1, $new-max-nodes)
      else
        // 没有下一层级了,当前层级就是最远的,返回所有节点
        $updated-current-level
};

// 查询尼加拉瓜的最远国家
let $furthest-countries := local:reachable-far($country[name="Nicaragua"])
return $furthest-countries/name

关键修改说明

  1. 新增$current-level-nodes参数:专门用来累积当前层级的所有节点,不会在层级切换时被清空,确保同深度的节点都被收集。
  2. 新增$max-depth-nodes参数:跟踪所有达到最大深度的节点,避免只返回最后一个处理的节点。
  3. 层级切换逻辑优化:当处理完当前层级最后一个节点时,先判断当前深度是否是最大的,再更新最大深度节点集合,然后才进入下一层级。
  4. 移除了不必要的union操作:用序列拼接($a, $b)代替,更高效且符合BFS节点收集的逻辑。

现在你再运行这个修改后的代码,查询尼加拉瓜应该就能得到加拿大、阿根廷等所有最远国家了,单独查询阿根廷也能正常工作。

内容的提问来源于stack exchange,提问作者Vamdinade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:36