更快的XPath表达式以执行来自多个XML的查询

时间:2019-08-11 03:28:04

标签: xpath xquery xpath-2.0 xpath-3.0

我有以下两种XML,问题说明如下。

  1. 解析XML 1,并且如果任何 node_x 的子节点的名称中包含“ a”(如 value_a_0 )和 value_a_0 包含一个特定数字,解析XML 2并转到所有 abc_x node_x-1 ,并比较 value_x-1_0 / 1/2/3 < / strong>和某些实体。

  2. 如果任何 node_x 的子节点名称中包含“ b”(例如 value_b_0 ),并且 value_b_0 中包含特定数字(例如'm'),解析XML 2并转到其中的所有 abc_x node_x + 1 并比较 value_x-1_0 / 1/2 / 3 和'm'。

示例:对于 record1 中的所有 value_a_0 ,检查 value_a_0 节点是否包含5。如果是,就是这种情况node_1 node_9 ,转到 record2 / node_0 record2 / node_8 并比较value_0_0 / 1/2/3的内容它们是否包含5。同样,对于其余情况。

我想知道解决该问题的最佳做法是什么? Xpath 3.0中是否有任何哈希表方法?

第一个XML

<record1>
    <node_1>
        <value_a_0>5</value_1_0>
        <value_b_1>0</value_1_1>
        <value_c_2>10</value_1_2>
        <value_d_3>8</value_1_3>
    </node_1>
   .................................
   .................................

    <node_9>
        <value_a_0>5</value_a_0>
        <value_b_1>99</value_b_1>
        <value_c_2>53</value_c_2>
        <value_d_3>5</value_d_3>
  </node_9>
</record1>

第二个XML

<record2>
  <abc_0>
        <node_0>
            <value_0_0>5</value_0_0>
            <value_0_1>0</value_0_1>
            <value_0_2>150</value_0_2>
            <value_0_3>81</value_0_3>
        </node_0>
        <node_1>
            <value_1_0>55</value_1_0>
            <value_1_1>30</value_1_1>
            <value_1_2>150</value_1_2>
            <value_1_3>81</value_1_3>
        </node_1>
       .................................
       .................................

        <node_63>
            <value_63_0>1</value_63_0>
            <value_63_1>99</value_63_1>
            <value_63_2>53</value_63_2>
            <value_63_3>5</value_63_3>
      </node_63>
   </abc_0>
   ================================================
   <abc_99>
        <node_0>
            <value_0_0>555</value_0_0>
            <value_0_1>1810</value_0_1>
            <value_0_2>140</value_0_2>
            <value_0_3>80</value_0_3>
        </node_0>            
        <node_1>
            <value_1_0>555</value_1_0>
            <value_1_1>1810</value_1_1>
            <value_1_2>140</value_1_2>
            <value_1_3>80</value_1_3>
        </node_1>
        <node_2>
            <value_2_0>5</value_2_0>
            <value_2_1>60</value_2_1>
            <value_2_2>10</value_2_2>
            <value_2_3>83</value_2_3>
        </node_2>
       .................................
       .................................

        <node_63>
            <value_63_0>1</value_63_0>
            <value_63_1>49</value_63_1>
            <value_63_2>23</value_63_2>
            <value_63_3>35</value_63_3>
       </node_63>
    </abc_99>
  </record2>

2 个答案:

答案 0 :(得分:4)

首先,我想说使用这样的结构化元素名称是非常糟糕的XML设计。这是相关的,因为当您在XPath或XQuery中执行联接查询时,您非常依赖优化器来查找快速执行路径(例如,哈希联接),并且查询“更奇怪”时,优化器执行的可能性越小找到快速执行策略。

我通常首先将“怪异”的XML转换为更卫生的东西。例如,在这种情况下,我会将<value_a_0>5</value_1_0>转换为<value cat="a" seq="0">5</value>。这样可以更轻松地编写查询,并使优化程序更易于识别查询,并且转换阶段是可重用的,因此您可以在对XML进行任何操作之前而不只是对XML进行操作。

如果要在联接查询上寻求优于O(n * m)的性能,则需要查看所选XPath引擎的功能。例如,Saxon-EE将进行此类优化,而Saxon-HE则不会。通常,您比XPath引擎更可能在XQuery引擎中找到高级优化。

关于查询的详细信息,当您开始谈论abc_x时,我对需求陈述感到迷惑。我不确定这是指什么。

答案 1 :(得分:2)

这似乎可以通过分组来部分解决,但正如您在前面的示例中一样,XML元素名称的使用不善,它们的不同之处在于索引值应该是元素或属性值的一部分,而不是元素名称的一部分使得编写简洁的代码更加困难:

let $abc-elements := $doc2/record2/*
for $node-element in record1/*
for $index in (1 to count($node-element[1]/*))
for $index-element in $node-element/*[position() = $index]
group by $index, $group-value := $index-element
where tail($index-element)
return 
    <group index="{$index}" value="{$group-value}">
    {
        let $suffixes := $index-element/../string((xs:integer(substring-after(local-name(), '_')) - 1)),
            $relevant-abc-node-elements := $abc-elements/*[substring-after(local-name(), '_') = $suffixes]
        return $relevant-abc-node-elements[* = $group-value]
    }
    </group>

https://xqueryfiddle.liberty-development.net/nbUY4kA