有条件地从XQuery中的元素和属性创建格式化字符串

时间:2015-06-11 10:28:21

标签: xquery

我正在尝试将xml文档转换为特定的制表符分隔的平面文件结构。大多数元素可以映射到单个列或简单地使用fn:string-join()连接,但我有一些元素,其中映射更复杂。示例元素如下所示:

<record>
  <details>
    <passports>
      <passport country="">0018061/104</passport>
      <passport country="UK">0354761445</passport>
      <passport country="USA">M001806145</passport>
    </passports>
  </details>
<record>

我需要创建一个如下所示的列:

  0018061/104;(UK) 0354761445;(USA) M001806145

因此,如果@country属性不是"",则会将其放入(),否则会被省略。元素值如下,每个元素由;分隔。

这是我到目前为止所做的:

for $record in //record
  return concat($record/@uid/string(),
  (: ... other columns ... :)
  "&#09;", <S>{for $r in //$record/details/passports/passport
    return concat("(", $r/@country, ") ", $r, ";")}</S>/string()
  ,"&#10;")

我确信这是一种更简单的方法,但这几乎可以完成工作 - 它会产生:

  () 0018061/104;(UK) 0354761445;(USA) M001806145

理想情况下,我想知道正确的方法,否则只需删除@country=""就足够的空括号。

1 个答案:

答案 0 :(得分:0)

在外部if中使用concat子句(为了更好的可读性,我添加了一些换行符,您当然可以根据需要删除它们):

concat(
  if ($r/@country != "")
  then concat("(", $r/@country, ") ")
  else "",
  $r,
  ";"
)

查询的新结果:

0018061/104; (UK) 0354761445; (USA) M001806145;

您也可以进行隐式循环

/record/details/passports/passport/string-join(
  (
    "&#09;",
    if (@country != "")
    then "(" || @country || ") "
    else (),
    .
  ), ""
)

或显式循环结果并仍然有一个更清晰的查询(通过相应的||调用替换连接运算符concat(...),您将保持XQuery 1.0兼容):

for $record in /record/details/passports/passport
return (
  "&#09;" || (
    if ($record/@country != "")
    then "(" || $record/@country || ") "
    else ()
  ) || $record
)

这两种情况都使用BaseX在令牌之间插入的隐式换行符,或者你可以像以前一样添加它们。