xml
How to handle recursion in XQuery?
I'm trying to find all countries which are reachable by land by traversing from one country to another via land borders using the mondial.sql database. It must be done recursively and I found some functions online which I thought would be useful for joining sequences and to be able to exclude countries which have already been found. The problem is I end up in a loop even though the countries that are to be excluded seems to be handled properly. So my thinking is that I might have to define a base case in some way to make the recursion stop once all possible countries have been found. How to achieve this with XQuery? (: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)
Your checks with $reachedCountries only guarantee that countries do not appear twice on the same path, but you still visit every country along every possible path, which takes a long time. There is no loop, just lots of redundancy. Here is a simple depth-first search that does what you want: 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
Related Links
Calculating Date Difference In XSLT-1.0
Batch script using file names from an XML file to organize sound files
CRM : Workflow : Modify hidden field
Auto check Allow external users to sign up in General settings page
highlight string of text between two XML tags (Crystal Reports 2016)
Can't select elements of specific type
Is their a “region-like” folding feature for xml editors
How to move two row values to column and respective row in xquery
pom.xml is not picking the variable from settings.xml
Generating XML for use with Salesforce SOAP API
Openerp-How to write access rules on fields separately
Copy everything except image and span Tag
xsl:result-document directory generation [duplicate]
how to avoid escaping of < and > in SoapUI
Use simple XML to load an XML file and then create a new one with the nodes I need from the one I loaded
How to get same element 2nd time came in same parent element