【问题标题】:How to change the outputted XML from a recursive function in XQuery?如何从 XQuery 中的递归函数更改输出的 XML?
【发布时间】:2018-11-15 16:30:59
【问题描述】:

我正在尝试在 mondial 数据库中递归地生成一个国家/地区的 XML 文档。该文件应说明您必须跨越多少个边界才能到达该国以及跨越的国家总数。

XML 应该如下所示:

    <from_swe_cross>
        <cross num="1" sum="2">
            <country>Finland</country>
            <country>Norway</country>
        </cross>
        <cross num="2" sum="3">
            <country>Russia</country>
        </cross>

我知道如何生成您可以前往的国家/地区列表,但不知道如何正确格式化,也知道已经过境的次数或过境的国家总数。

我现在的代码是:

declare function local:crossing($stack, $seen, $level, $sum) {
  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:crossing(($neighbors, $stack[position() > 1]), ($seen, $neighbors), $level + 1, $sum + count($neighbors))
  )
};

<from_swe_cross>{
  local:crossing(db:open('mondial')//country[@car_code = 'S'], db:open('mondial')//country[@car_code = 'S'], 1, 0)/name
}
</from_swe_cross>

但这仅列出了您可以穿越的所有国家/地区,如下所示:

<from_swe_cross>
  <name>Albania</name>
  <name>Greece</name>
  <name>Macedonia</name>
  <name>Serbia</name>
  <name>Montenegro</name>
  ...
</from_swe_cross>

如何生成正确的 XML?

【问题讨论】:

    标签: xml recursion xquery


    【解决方案1】:

    一种解决方案是使用累积参数来收集结果序列,从一个空序列开始:

    declare function local:crossing($stack, $seen, $level, $sum, $out) {
      if(empty($stack)) then $out
      else (
        let $country := $stack[1]
        let $neighbors :=
            for $code in $country/border/@country[not(. = $seen/@car_code)]
            return $country/../country[@car_code = $code]
        let $sum := $sum + count($neighbors)
        return local:crossing(
          ($neighbors, $stack[position() > 1]),
          ($seen, $neighbors),
          $level + 1,
          $sum,
          ($out, <cross num="{$level}" sum="{$sum}">{$neighbors/name}</cross>)
        )
      )
    };
    <from_swe_cross>{
      local:crossing(
        db:open('mondial')//country[@car_code = 'S'],
        db:open('mondial')//country[@car_code = 'S'],
        1, 0, ()
      )
    }
    </from_swe_cross>
    

    结果看起来就像你在上面显示的那样:

    <from_swe_cross>
      <cross num="1" sum="2">
        <name>Finland</name>
        <name>Norway</name>
      </cross>
      <cross num="2" sum="3">
        <name>Russia</name>
      </cross>
      <cross num="3" sum="15">
        <name>Belarus</name>
        <name>Latvia</name>
        <name>Lithuania</name>
        <name>Poland</name>
        <name>Ukraine</name>
        <name>Estonia</name>
        <name>China</name>
        ...
    

    未找到新目的地的步骤显示为空的cross 元素。如果你愿意,你可以压制那些。

      ...
      <cross num="4" sum="15"/>
      <cross num="5" sum="15"/>
      <cross num="6" sum="15"/>
      <cross num="7" sum="18">
        <name>Czech Republic</name>
        <name>Germany</name>
        <name>Slovakia</name>
      </cross>
      ...
    

    【讨论】:

    • 谢谢,这正是我要找的,但我怎样才能抑制空的交叉元素?
    • 只需将($out, &lt;cross num="{$level}" sum="{$sum}"&gt;{$neighbors/name}&lt;/cross&gt;) 替换为if(empty($neighbors)) then $out else ($out, &lt;cross num="{$level}" sum="{$sum}"&gt;{$neighbors/name}&lt;/cross&gt;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 2011-02-16
    相关资源
    最近更新 更多