如何使用Xquery在XML中循环多个元素

时间:2017-09-07 19:52:04

标签: xquery

我有以下XML

<Item>
  <line>1</line>
  <itemno>ABC</itemno>
  <qty>3</qty>
  <serialnos>
    <serial>ABC1</serial>
    <serial>ABC2</serial>
    <serial>ABC3</serial>
  </serialnos>
  <Trackingnos>
    <trno>ABCT1</trno>
    <trno>ABCT2</trno>
    <trno>ABCT3</trno>
  </Trackingnos>
</Item>

现在问题是我已将它们转换为以下格式

<Line>
<opn>ABC</opn>
<qty>3</qty>
<serialCollection>
 <serials>
   <lineno>1</lineno>
   <serial>ABC1</serial>
   <trk>ABCT1</trk>
 </serials>
<serials>
   <lineno>1</lineno>
   <serial>ABC2</serial>
   <trk>ABCT2</trk>
 </serials>
<serials>
   <lineno>1</lineno>
   <serial>ABC3</serial>
   <trk>ABCT3</trk>
 </serials>
</serialCollection>
</Line>

我遇到的问题是源xml中的序列号和跟踪号的组合可能会有所不同。 例如: 可以有3个连续出版物,跟踪编号只能是1 要么 可以有3个连续出版物,跟踪编号可以是3 要么 没有连续出版物,跟踪号码可以是3 要么 没有连续出版物,跟踪号可以是2

如果跟踪号和序列号相等,那么我可以一对一分配。 如果跟踪号码小于序列号,那么我必须随机选择最后一个跟踪号并将其分配给剩余的序列号。

如果没有连续剧,则下面是输出

 <Line>
    <opn>ABC</opn>
    <qty>3</qty>
    <serialCollection>
     <serials>
       <lineno>1</lineno>
       </serial>
       <trk>ABCT1</trk>
     </serials>
    <serials>
       <lineno>1</lineno>
       </serial>
       <trk>ABCT2</trk>
     </serials>
    <serials>
       <lineno>1</lineno>
       </serial>
       <trk>ABCT3</trk>
     </serials>
    </serialCollection>
    </Line>

同样,如果没有追踪号码,那么它们就是空的。

我必须在Xquery中进行此转换,但我无法做到这一点。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

如果我了解您的要求,则serialCollection将始终包含等于跟踪号码数量或序列号数量的serial元素,以较大者为准。您可以使用fn:max计算,并迭代生成的数字序列以创建正确数量的元素。

接下来,您要选择与序列中位置对应的跟踪编号和序列号,除非该位置的跟踪编号为空,在这种情况下您要选择最后一个跟踪编号。生成包含两个元素的序列并选择序列的第一个项目。如果第一个为空,则将选择第二个。

declare function local:transform(
  $item as element(Item)
) as element(Line)
{
  element Line {
    $item/itemno/element opn { string() },
    $item/qty
    ,
    let $tracking-numbers := $item/Trackingnos/trno
    let $serial-numbers := $item/serialnos/serial
    let $len := max((count($tracking-numbers), count($serial-numbers)))
    where ($len gt 0)
    return element serialCollection {
      for $i in (1 to $len)
      return element serials {
        $item/line/element lineno { string() },
        element serial { $serial-numbers[$i]/string() },
        element trk { ($tracking-numbers[$i], $tracking-numbers[last()])[1]/string() }
      }
    }
  }
};