如何在XQuery结果中避免重复?

时间:2021-06-03 04:19:52

This is newbie question. I am just start learning XQuery and XPath recently.

这是新手的问题。我最近刚刚开始学习XQuery和XPath。

Consider this XML

考虑这个XML

<employees>
<employee empid="1">
    <ename>KING</ename>
    <mgr></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>

When I execute the following XQuery,

当我执行以下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'.

这是因为sub1只存在于/employee/@empid='2'中。

Can someone please point me to the right direction? Thanks

谁能给我指出正确的方向吗?谢谢

2 个解决方案

#1


3  

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.

$item1遍历所有员工/员工元素,$item2遍历所有员工/员工/测试元素,与$item1的当前值无关。

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)

#2


1  

Here is one way to do it. Before returning, check with an if statement whether test/sub1 exists or not.

这里有一个方法。在返回之前,检查if语句是否存在test/sub1。

I slightly changed the for clause as well, removing the db:open() function, but it's easy to add it back in.

我还稍微修改了for子句,删除了db:open()函数,但是很容易将它添加回。

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:

另一种稍微不同的方法是使用if/then/else XPath表达式,并无条件地返回这个表达式:

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!

CiaPan给出的答案是另一种方式,这次是嵌套子句。在我看来,这有点不太直接,但还是有效的。CiaPan还展示了单个XPath表达式如何可能解决问题——这非常简单!

#1


3  

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.

$item1遍历所有员工/员工元素,$item2遍历所有员工/员工/测试元素,与$item1的当前值无关。

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)

#2


1  

Here is one way to do it. Before returning, check with an if statement whether test/sub1 exists or not.

这里有一个方法。在返回之前,检查if语句是否存在test/sub1。

I slightly changed the for clause as well, removing the db:open() function, but it's easy to add it back in.

我还稍微修改了for子句,删除了db:open()函数,但是很容易将它添加回。

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:

另一种稍微不同的方法是使用if/then/else XPath表达式,并无条件地返回这个表达式:

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!

CiaPan给出的答案是另一种方式,这次是嵌套子句。在我看来,这有点不太直接,但还是有效的。CiaPan还展示了单个XPath表达式如何可能解决问题——这非常简单!