Judah Flynn
Judah Flynn

Reputation: 544

xQuery how to merge two list into one?

I have an XML document:

<resultsets>
    <row>
        <emp_no>10001</emp_no>
        <first_name>Georgi</first_name>
        <last_name>Facello</last_name>
    </row>
    <row>
        <emp_no>10002</emp_no>
        <first_name>Bezalel</first_name>
        <last_name>Simmel</last_name>
    </row>
    <row>
        <emp_no>10003</emp_no>
        <first_name>Parto</first_name>
        <last_name>Bamford</last_name>
    </row>
</resultsets>

Currently, my code is as follows:

let $first := doc("db/apps/flowq/index/employees.xml")//first_name
let $last := doc("db/apps/flowq/index/employees.xml")//last_name

My question is, is it possible ONLY use $first and $last to generate the following result?

<row>
    <first_name>Georgi</first_name>
    <last_name>Facello</last_name>
 </row>
 <row>
    <first_name>Bezalel</first_name>
    <last_name>Simmel</last_name>
 </row>
 <row>
    <first_name>Parto</first_name>
    <last_name>Bamford</last_name>
 </row>

Basically, if we have two lists of nodes same size, how can we merge them one by one? I have tried ($first_name, $last_name) and ($first_name union $last_name) but doesn't work,

thanks!

Upvotes: 0

Views: 1173

Answers (2)

Michael Kay
Michael Kay

Reputation: 163352

And of course for FP afficionados there's the basic recursive function:

declare function local:merge($s1, $s2) {
  if ($s1 and $s2) 
  then (<row>{head($s1), head($s2)}</row>, 
        local:merge(tail($s1), tail($s2)))
  else ()
}

Upvotes: 3

Martin Honnen
Martin Honnen

Reputation: 167581

It is a bit odd that you first extract the two different sequences from the same document but in general if you want positional merging then using for $item at $pos can help:

let $first := (
    <first_name>Georgi</first_name>,
    <first_name>Bezalel</first_name>,
    <first_name>Parto</first_name>),
$second := (
    <last_name>Facello</last_name>,
    <last_name>Simmel</last_name>,
    <last_name>Bamford</last_name>
    )
return for $name at $pos in $first
       return
          <row>
              {$name, $second[$pos]}
          </row>

http://xqueryfiddle.liberty-development.net/eiQZDbb

Or use higher-order for-each-pair:

let $first := (
    <first_name>Georgi</first_name>,
    <first_name>Bezalel</first_name>,
    <first_name>Parto</first_name>),
$second := (
    <last_name>Facello</last_name>,
    <last_name>Simmel</last_name>,
    <last_name>Bamford</last_name>
    )
return for-each-pair($first, $second, function($f, $s) { <row>{$f, $s}</row>})

Upvotes: 1

Related Questions