如何在选择元素类型xquery上比较深度节点,搜索具有匹配子元素的节点?

时间:2018-04-21 15:05:23

标签: xquery

假设我将拥有2个xml文档 XML1

<req>
    <a name="1">
        <a name="2"/>
    </a>
</req>

和 XML2

<r>
    <b id="1">
        <a name="1">
            <a name="2"/>
        </a> 
    </b>
    <b id="2">
        <a name="3">
            <a name="4">
                <a name="5"/>
            </a>
        </a> 
    </b>
</r>

我想要做的是使用xml1作为搜索要包含的元素所需节点的列表。在中,我想只返回那些只包含那些在xml1中指定的子元素“a”的“b”元素而没有其他元素(它仍然可以包含具有不同名称的其他元素),但是我想要弄清楚如何确保“a”的每个子元素也被指定为“a”而不是其他元素。

基本上我只能找到那些在“xml1”中指定“a”元素的“b”元素,并且具有完全相同的“a”子元素(可以忽略任何其他元素)

for $r in $xml2/r/b
where (every $a 
        in $r/a 
        satisfies $a/@name = $xml1/req/a/@name)
return $r

到目前为止我尝试了什么,但如果我理解正确,这应该只检查第一层

编辑:以防万一,更好的搜索规则规范:“b”节点是一个结果节点,当且仅当它包含所有且仅包含xml1中指定的“a”节点和两个“a”节点时如果它们具有相同的名称和相同的“a”节点子节点,则它们是相同的。

编辑2: 为澄清,以下两个“b”相等

<r>
    <b id="1">
        <a name="1">
            <a name="2"/>
        </a> 
    </b>
</r>

<r>
    <b id="1">
        <a name="1">
            <a name="2"/>
            <d/>
        </a> 
        <c/>
    </b>
</r>

1 个答案:

答案 0 :(得分:1)

以下解决方案假设每个级别上可能有多个a元素,并且它假定这些元素的顺序必须相同:

declare variable $xml1 := <req>...</req>;
declare variable $xml2 := <r>...</r>;

declare function local:deep-equal-a($xml, $find) {
  let $xas := $xml/a, $fas := $find/a
  return count($xas) = count($fas) and (
    every $test in for-each-pair($xas, $fas, function($xa, $fa) {
      $xa/@name = $fa/@name and local:deep-equal-a($xa, $fa)
    }) satisfies $test
  )
};

for $b in $xml2/b
where local:deep-equal-a($b, $xml1)
return $b

如果每个级别最多只有一个a元素,则可以简化查询:

declare function local:deep-equal-a($xml, $find) {
  let $xa := $xml/a, $fa := $find/a
  return not($xa and $fa) or
    $xa/@name = $fa/@name and local:deep-equal-a($xa, $fa)
};