XQuery:除最后一个元素外,如何在序列后添加逗号

XQuery: How to add a comma after sequence except for the last element

我有以下 xml:

<form>
<bibl>
    <biblScope>1</biblScope>
    <biblScope>a</biblScope>
</bibl>
<bibl>
    <biblScope>2</biblScope>
    <biblScope>b</biblScope>
</bibl>
<bibl>
    <biblScope>38</biblScope>
    <biblScope>c</biblScope>
</bibl>
</form>

使用这个 XQuery

for $bibl in form/bibl 
return
<div>
{
for $biblScope in $bibl/biblScope/text()
    return
    $biblScope
}
{if ($bibl[position()] ne $bibl[last()]) then ',' else '@'}
</div>  

<biblScope>内容陆续打印出来。在每个 bibl 元素之后,除了最后一个,我想添加一个分隔符(逗号/“,”),但是使用上面的代码,我得到的只是

<div>
1a
@
</div>
<div>
2b
@
</div>
<div>
38c
@
</div>

这绝对是错误的,因为我想要的是

<div>1a,</div>
<div>2b,</div>
<div>38c@</div>

(在每个 bibl 元素内容后添加一个逗号;最后一个应该跟在 @ 而不是逗号。)

我已经尝试了一段时间不同的东西,可能需要一些帮助。执行此操作的正确方法是什么?

首先注意这个:

for $biblScope in $bibl/biblScope/text()
    return
    $biblScope

可以这样代替:

$bibl/biblScope/text()

(这一点冗长是一个令人惊讶的常见错误。它表明您是在按程序思考 - 一次处理一个项目,而不是处理集合。)

然后这个:

<div>
{$bibl/biblScope/text()}
{if ($bibl[position()] ne $bibl[last()]) then ',' else '@'}
</div> 

应替换为:

<div>{string-join($bibl/biblScope, ',')}@</div>

请注意,我还摆脱了对 /text() 的不必要(并且可以说是不正确的)使用,这是另一个 XQuery anti-pattern.

问题是 position()last() 作用于当前上下文,它不是由 flwor 表达式设置的。如果你想使用类似的语义,使用 at $position 语法得到一个位置计数器,并定义 $last 作为结果的数量:

let $last := count(form/bibl)
for $bibl at $position in form/bibl 
return
<div>
{
for $biblScope in $bibl/biblScope/text()
    return
    $biblScope
}
{if ($position ne $last) then ',' else '@'}
</div>  

如果您能够使用 XQuery 3.0,应用程序运算符 ! 可能会在这里派上用场。用轴步骤和元素构造函数替换不必要的循环,您可以依赖位置谓词,因为上下文设置为 <bibl/> elements:

form/bibl ! <div>
{
  biblScope/text(),
  if (position() ne last()) then ',' else '@'
}
</div>