0
votes

I'm trying to finish a school homework question about finding the most distant country(-ies) regarding number of border crossing using BaseX GUI and mondial database. I wrote a recursive function using BFS to complete this. The query should return a bunch of country names that are most distant to the input country.

When I called the function as below to find the most distant country to Nicaragua, a bunch of country names including "Canada" and "Argentina" should be returned.

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

However, I only got Canada in my return value but not other countries, like Argentina or Suriname.

<name>Canada</name>

I tried to debug the query by calling

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

The return value is

<name>Argentina</name>

which I think means Argentina (and other countries) is in the return value but somehow not showing. What's wrong with my code here? The full function declaration is pasted below.

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
It looks to me as if the problem might be in the way you invoke the query and display the results, which you haven't told us anything about. You could also try wrapping the results into a single element, with return <out>{$return-list/country/name}</out>Michael Kay
I have tried your query in oXygen using the XQuery evaluator and Saxon as the XQuery processor and then in BaseX GUI and both return the same sequence of 9 country names.Martin Honnen
This might be related to a specific release of BaseX (I guess it happens with 9.0.1?). I’ll come back to you as soon as I know more.Christian Grün

1 Answers

0
votes

In BaseX 9.0.1 (which is the current version, and probably the one you were using), the node id ordering algorithm has a small bug. BaseX 9.0 or the latest snapshot (http://files.basex.org/releases/latest/) should yield the expected result. BaseX 9.0.2 will be available end of May 2018.