2017-05-07 16 views
4

私はmondial.sqlデータベースを使って国境を越えてある国から別の国へ移動することで、土地に到達可能なすべての国を探しています。それは再帰的に行われなければならず、シーケンスに参加し、すでに見つかった国を除外できるようになると私は考えていたオンラインの関数をいくつか見つけました。XQueryで再帰を処理する方法は?

除外対象の国が適切に処理されているように見えるにもかかわらず、問題はループ状になります。だから私の考えは、すべての可能な国が見つかったら再帰を止める何らかの方法で基底ケースを定義しなければならないかもしれないということです。 XQueryでこれを達成する方法は? $reachedCountries

(:functx.value-union and is-value-in-sequence were found at http://www.xqueryfunctions.com/xq/:) 
declare namespace functx = "http://www.functx.com"; 
declare function functx:value-union 
    ($arg1 as xs:anyAtomicType* , 
    $arg2 as xs:anyAtomicType*) as xs:anyAtomicType* { 

    distinct-values(($arg1, $arg2)) 
}; 

declare function functx:is-value-in-sequence 
    ($value as xs:anyAtomicType? , 
    $seq as xs:anyAtomicType*) as xs:boolean { 

    $value = $seq 
} ; 

(:Recursive function for finding reachable countries:) 
declare function local:findReachable($countries, $country, $reachedCountries) { 
    let $reachableCountries := $countries[@car_code = $country/border/@country] 
    for $c in $reachableCountries 
    where not(functx:is-value-in-sequence($c, $reachedCountries)) 
    return functx:value-union($c, local:findReachable($countries, $c, functx:value-union($reachableCountries, 
    $reachedCountries))) 
}; 

let $countries := //country 
let $startingCountry := //country[@car_code = 'S'] 
return local:findReachable($countries, $startingCountry, $startingCountry) 

答えて

6

あなたのチェックが唯一の国が同じパスに二回を表示されませんが、あなたはまだ長い時間がかかる可能なすべてのパスに沿ってすべての国を訪問することを保証します。ループはなく、多くの冗長性があります。ここで

は何をしたいんシンプル深さ優先探索です:

declare function local:dfs($stack, $seen) { 
    if(empty($stack)) then $seen 
    else (
    let $country := $stack[1] 
    let $neighbors := 
     for $code in $country/border/@country[not(. = $seen/@car_code)] 
     return $country/../country[@car_code = $code] 
    return local:dfs(($neighbors, $stack[position() > 1]), ($seen, $neighbors)) 
) 
}; 

local:dfs(doc('mondial.xml')//country[@car_code = 'S'],())/name 
関連する問題