使用XQuery进行递归并举例说明

使用XQuery进行递归并举例说明,xquery,Xquery,我有一个类似这样的数据库(通过$database访问它): 对该函数的调用: local:reachable($database/country[@car_code = "F"]) 与法国接壤的国家应为: <border country="AND" length="60"/> <border country="E" length="623"/> <border country="D" length="451"/> <border cou

我有一个类似这样的数据库(通过
$database
访问它):

对该函数的调用:

local:reachable($database/country[@car_code = "F"])
与法国接壤的国家应为:

  <border country="AND" length="60"/>
  <border country="E" length="623"/>
  <border country="D" length="451"/>
  <border country="I" length="488"/>
  <border country="CH" length="573"/>
  <border country="B" length="620"/>
  <border country="L" length="73"/>
  <border country="MC" length="4.4"/>

但我们也需要为这些国家找到边界国家。 最终输出应为“F”、“和”、“E”、“D”、“I”、“CH”、“B”、“L”、“MC”…、X、Y、Z(以及与这些国家接壤的其他国家)

  • 我知道联盟没有定义,但还有什么我可以使用的吗?我只是想更清楚地知道我想做什么

  • 除了语法错误之外,还有一个大问题,那就是如果“F”与“L”相邻,那么“L”将与“F”相邻,所以我的“函数”永远不会终止——我该如何处理

  • 我能得到一些语法方面的帮助吗

  • 如果问题不清楚,请让我知道,以便我进一步澄清

在我们开始之前 以下是对您的代码的一些评论:

  • $country as element()
    定义一个变量,该变量必须包含 只有一个元素,所以它永远不能为空;如果需要,请使用
    element()?
    元素是可选的,
    element()*
    如果可以有任意数量的 它们,或者如果必须有一个或多个元素,则为
    element()+

  • 序列运算符
    可用于从 其他序列:
    (1,2)、(3,4)
    构造2个序列:
    (1,2)
    (3,4)
    ,然后构造另一个包含 其他,导致:
    (1,2,3,4)

资料 让我稍微更改
countries
元素,以便消除噪声, 让这个演示变得简单一点。此外,我还创建了一个 简单但完整的地图。让我们假设我们有两个相邻的国家 K和其他4个组成正方形(每个国家相邻2个) 其他):N、G、B和F。与现有地理或 政治只在你眼中:-)


夸张的
遥不可及
平地
马霍姆
蜂房
葡萄饼
解决方案 该解决方案包括一个递归函数,该函数使用 需要处理的国家。同时,它将结果列表累加为1 一次一个国家。它取队列中的第一个国家,将其添加到 然后,结果会在所有不受影响的邻国重现 已在队列中,也不是当前结果。扩大的结果是 也传下来了

xquery version "3.0";

declare variable $countries :=
<countries>
   <!-- as above, just copy and paste it -->
</countries>;

declare function local:reachable(
   $queue  as element(country)*,
   $result as element(country)*   
) as element(country)*
{
   if ( empty($queue) ) then (
      (: we do not consider one country reachable from itself :)
      tail($result)
   )
   else (
      let $this := head($queue)
      let $rest := tail($queue)
      let $more := $this/border/@idref[not(. = ($queue, $result)/@id)]
      return
         local:reachable(
            ( $rest, $countries/country[@id = $more] ),
            ( $result, $this ))
   )
};

(: for each countries, display its reachable countries
 :)
for $c in $countries/country
order by $c/@id
let $r := local:reachable($c, ())
return
   $c/name || ': ' || string-join($r/@id, ', ')

这给了我很多的快乐-很好!您的评论也是:-)
  <border country="AND" length="60"/>
  <border country="E" length="623"/>
  <border country="D" length="451"/>
  <border country="I" length="488"/>
  <border country="CH" length="573"/>
  <border country="B" length="620"/>
  <border country="L" length="73"/>
  <border country="MC" length="4.4"/>
xquery version "3.0";

declare variable $countries :=
<countries>
   <!-- as above, just copy and paste it -->
</countries>;

declare function local:reachable(
   $queue  as element(country)*,
   $result as element(country)*   
) as element(country)*
{
   if ( empty($queue) ) then (
      (: we do not consider one country reachable from itself :)
      tail($result)
   )
   else (
      let $this := head($queue)
      let $rest := tail($queue)
      let $more := $this/border/@idref[not(. = ($queue, $result)/@id)]
      return
         local:reachable(
            ( $rest, $countries/country[@id = $more] ),
            ( $result, $this ))
   )
};

(: for each countries, display its reachable countries
 :)
for $c in $countries/country
order by $c/@id
let $r := local:reachable($c, ())
return
   $c/name || ': ' || string-join($r/@id, ', ')
Beerium: N, G, F
Grapeandcheese: N, G, B
Marxhome: N, B, F
Beyond the see: U
Flatland: G, B, F
Over the top: K