我有一个看起来像这样的数据库(通过$database
访问它):
<country car_code="F" area="547030" capital="cty-france-paris">
<name>France</name>
<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"/>
</country>
.....
other countries
我想写一个功能,通过陆地边界提供从法国(或任何其他国家)可以到达的所有国家的名称。第一次尝试(可能有很多语法错误和其他错误,但程序的语义应该“更清楚”):
declare function local:reachable($country as element())
as (return value should be a sequence of countries )
{
if $country == () (:if empty, it doesn't border to any other country:)
then ()
else(
$country/name UNION (for $bord in $country/border/@country return
local:reachable ($database/country/car_code = @bord ))
)
}
对该功能的调用:
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”,“AND”,“E”,“D”,“I”,“CH”,“B”,“L”,“MC”......,X,Y,Z, (以及与这些国家接壤的其他国家)。
我知道UNION没有定义,但还有什么我可以使用吗?我只是想让它更清楚我想做什么
除了语法错误之外,一个大问题是,如果“F”与“L”接壤,那么“L”将与“F”接壤,因此我的“功能”永远不会终止 - 我该如何处理是什么?
我可以从语法
如果问题不明确请告诉我,以便我可以进一步澄清
答案 0 :(得分:5)
以下是对您的代码的一些评论:
$country as element()
定义了必须包含的变量
恰好是一个元素,所以它永远不会是空的;使用element()?
if
如果可以有任意数量的元素,则该元素是可选的element()*
他们,或element()+
,如果必须有一个或多个
序列运算符,
可用于构造序列
其他序列:(1,2) , (3,4)
构造2个序列:(1,2)
和
(3,4)
,然后构造包含所有项目的另一个
其他人,导致:(1,2,3,4)
让我略微改变countries
元素,所以我删除了噪音,
并使这个演示更简单一点。另外,我创建了一个
简单但完整的地图。我们说我们有两个相邻的国家
和K,以及另外4个形成一个正方形(每个国家的邻居都是2
其他):N,G,B和F.与现有地理或任何地理相似
政治只在你眼中: - )
<countries>
<country id="U">
<name>Over the top</name>
<border idref="K"/>
</country>
<country id="K">
<name>Beyond the see</name>
<border idref="U"/>
</country>
<country id="N">
<name>Flatland</name>
<border idref="B"/>
<border idref="G"/>
</country>
<country id="G">
<name>Marxhome</name>
<border idref="N"/>
<border idref="F"/>
</country>
<country id="B">
<name>Beerium</name>
<border idref="N"/>
<border idref="F"/>
</country>
<country id="F">
<name>Grapeandcheese</name>
<border idref="B"/>
<border idref="G"/>
</country>
</countries>
该解决方案包含一个消耗队列的递归函数 国家要处理。同时,它累积结果列表一 国家/地区。它将队列中的第一个国家/地区添加到其中 结果,然后递归所有相邻的国家 已经在队列中,也没有当前的结果。增强的结果是 也传了下来。
xquery version "3.0";
(: Map:
: U K | N G
: B F
:)
declare variable $countries :=
<countries>
<country id="U">
<name>Over the top</name>
<border idref="K"/>
</country>
<country id="K">
<name>Beyond the see</name>
<border idref="U"/>
</country>
<country id="N">
<name>Flatland</name>
<border idref="B"/>
<border idref="G"/>
</country>
<country id="G">
<name>Marxhome</name>
<border idref="N"/>
<border idref="F"/>
</country>
<country id="B">
<name>Beerium</name>
<border idref="N"/>
<border idref="F"/>
</country>
<country id="F">
<name>Grapeandcheese</name>
<border idref="B"/>
<border idref="G"/>
</country>
</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