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

Conditionally creating formatted string from elements and attributes in 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="" 就足够的空括号。

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

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 中间标记插入的隐式换行符,或者您当然可以像以前一样添加它们。