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

Faster XPath expressions to execute queries from multiple XMLs

我有下面两个XML,问题陈述如下。

  1. 解析 XML 1 并且如果任何 node_x 的子节点在其名称中包含 'a'(如 value_a_0) 和 value_a_0 包含特定数字,解析 XML 2 并转到 node_x-1对所有abc_x中和比较value_x-1_0/1/2/3[=50=的内容] 与某些实体。

  2. 如果任何 node_x 的子节点名称中包含 'b'(如 value_b_0) 和 value_b_0 包含特定数字(比如 'm'),解析 XML 2 并转到 node_x+1对所有abc_x中的内容进行比较value_x-1_0/1/2/3 与 'm'.

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

我想知道解决它的最佳做法是什么? Xpath 3.0 中是否有 hash-table 方法?

第一个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>

首先我要说的是,使用这样的结构化元素名称是非常糟糕的 XML 设计。这是相关的,因为当您在 XPath 或 XQuery 中执行连接查询时,您非常依赖优化器来找到快速执行路径(例如哈希连接),而您的查询 "weirder" ,优化器不太可能就是找一个快速执行的策略。

我通常先将 "weird" XML 转换成更卫生的东西。例如,在这种情况下,我会将 <value_a_0>5</value_1_0> 转换为 <value cat="a" seq="0">5</value>。这使得编写查询更容易,优化器更容易识别它,并且转换阶段是可重复使用的,因此您可以在 XML 上的任何操作之前应用它,而不仅仅是这个。

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

至于你的查询细节,当你开始谈论 abc_x 时,我对需求陈述感到困惑。我不确定那指的是什么。

这似乎是一项可以通过分组部分解决的任务,但在您之前的示例中,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