Reputation: 1256
This is newbie question. I am just start learning XQuery and XPath recently.
Consider this XML
<employees>
<employee empid="1">
<ename>KING</ename>
<mgr/>
<hiredate>17-11-1981</hiredate>
</employee>
<employee empid="2">
<ename>BLAKE</ename>
<mgr>7839</mgr>
<hiredate>1-5-1981</hiredate>
<test>
<sub1>one</sub1>
<sub2>two</sub2>
</test>
</employee>
</employees>
When I execute the following XQuery,
let $db := db:open("example")
for $item1 in $db/employees/employee,
$item2 in $db/employees/employee/test
return ($item1/mgr,$item1/ename,$item2/sub1)
I got...
<mgr/>
<ename>KING</ename>
<sub1>one</sub1>
<mgr>7839</mgr>
<ename>BLAKE</ename>
<sub1>one</sub1>
The result that I am hoping to get is...
<mgr/>
<ename>KING</ename>
<mgr>7839</mgr>
<ename>BLAKE</ename>
<sub1>one</sub1>
This is because sub1 only exist in /employee/@empid='2'.
Can someone please point me to the right direction? Thanks
Upvotes: 2
Views: 456
Reputation: 22617
Here is one way to do it. Before returning, check with an if
statement whether test/sub1
exists or not.
I slightly changed the for clause as well, removing the db:open()
function, but it's easy to add it back in.
for $employee in /employees/employee
return
if ($employee/test/sub1)
then
($employee/mgr, $employee/ename, $employee/test/sub1)
else
($employee/mgr, $employee/ename)
and the result will be
<mgr/>
<ename>KING</ename>
<mgr>7839</mgr>
<ename>BLAKE</ename>
<sub1>one</sub1>
You said there is more than one ways to do this, can you please describe further
A slightly different approach would be to use an if/then/else
XPath expression and unconditionally returning this expression:
for $employee in /employees/employee
return
($employee/mgr, $employee/ename, if ($employee/test/sub1) then $employee/test/sub1 else '')
And the answer by CiaPan shows yet another way, this time by nesting for
clauses. In my opinion, it is a little less straightforward but it works nevertheless. CiaPan also shows how a single XPath expression can potentially solve the problem - which is very straightforward!
Upvotes: 1
Reputation: 9570
In your for
expression
for $item1 in $db/employees/employee,
$item2 in $db/employees/employee/test
$item1
iterates through all the employees/employee
elements, and $item2
iterates through all the employees/employee/test
elements, independent of what the current value of $item1
is.
To get what you need you might try this:
for $item1 in $db/employees/employee,
return ($item1/mgr,$item1/ename,
for $item2 in $item1/test
return $item2/sub1)
or, shorter:
$db/employees/employee/(mgr, ename, test/sub1)
Upvotes: 3