【问题标题】:Can I make this xpath search faster?我可以让这个 xpath 搜索更快吗?
【发布时间】:2011-11-03 07:04:03
【问题描述】:
<root>
  <a auto='1'>
    <b>
      <c auto="1">
        <d auto="1"></d>
      </c>
    </b>
    <e auto="1">
      <f>
        <g auto="1"></g>
      </f>
    </e>
  </a>
</root>

找到所有的元素

  1. 是上下文元素的后代
  2. auto属性
  3. 最高级别(在 self 和上下文元素之间没有具有 auto 属性的祖先)

因此,如果上下文节点是a,则应返回ce

我已经在我的 php 类中实现了它:

$tempId='XDFAY69LA';
$this->setAttribute('tempId',$tempId);
$path=".//\*[@auto and not(ancestor::\*[@auto and ancestor::\*[@tempId='$tempId']])]";
$ar=$this->getElementsByXPath($path);
$this->removeAttribute('tempId');

但是我发现查询很慢,也许..,因为查询太复杂了?,有没有办法做得更好?


我写了一个测试,请看一下:

<?php
  $xml='
    <root>
      <a auto="1" tempId="current">
        <b>
          <c auto="1">
            <d auto="1"></d>
          </c>
        </b>
        <e auto="1">
          <f>
            <g auto="1"></g>
          </f>
        </e>
      </a>
    </root> ';

  $doc=new DomDocument();
  $tempId='XDFAY69LA';
  $doc->loadXml($xml);
  $domxpath=new DOMXPath($doc);
  $a=$domxpath->query('a')->item(0);
  $path=".//*[@auto and not(ancestor::*[@auto and ancestor::*[@tempId='$tempId']])]";
  $start=microtime(true);
  for($n=0;$n<1000;$n++){ //run 1000 times
    $a->setAttribute('tempId',$tempId);
    $ar=$domxpath->query($path,$a);
    $a->removeAttribute('tempId');
    for($i=0;$i<$ar->length;$i++){
      $node=$ar->item($i);
      //echo $node->tagName . "\n";
    }
  }
  $cost=round(1000 * (microtime(true)-$start));
  echo "time cost: $cost";
?>

【问题讨论】:

  • 好问题,+1。请参阅我的答案以获得更短的 XPath 表达式以及使用 XSLT 和键的更快解决方案的演示。如果您被禁止使用 XSLT,您可以使用哈希表实现类似的解决方案。

标签: xml xpath php-5.2


【解决方案1】:

使用

.//*[@auto and $tempId = ancestor::*[@auto][1]/@tempId]

这将选择所有具有auto 属性的后代元素(上下文节点),并且其第一个具有auto 属性的祖先元素也具有与tempId 属性值相同的tempId 属性上下文节点(后者存储在$tempId 变量中)。

这里我们假设没有两个不同元素的tempId 属性值相同。

基于 XSLT 的快速验证

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="a">
   <xsl:variable name="tempId" select="@tempId"/>

     <xsl:copy-of select=
      ".//*[@auto and $tempId = ancestor::*[@auto][1]/@tempId]"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时

<root>
    <a auto="1" tempId="current">
        <b>
            <c auto="1">
                <d auto="1"></d>
            </c>
        </b>
        <e auto="1">
            <f>
                <g auto="1"></g>
            </f>
        </e>
    </a>
</root>

生成所需的正确结果(ce 两个元素)

<c auto="1">
   <d auto="1"/>
</c>
<e auto="1">
   <f>
      <g auto="1"/>
   </f>
</e>

只能在 XPath 表达式中提高性能,效率低下是因为必须使用 // XPath 伪运算符。

如果使用 XSLT,可以使用键获得有效的解决方案

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kfirstDescendents" match="*[@auto]"
  use="generate-id(ancestor::*[@auto][1])"/>

 <xsl:template match="a">
     <xsl:copy-of select=
      "key('kfirstDescendents', generate-id())"/>
 </xsl:template>
</xsl:stylesheet>

此转换产生与第一个相同的结果,并且在包含许多具有auto 属性的嵌套元素的文档上明显更快

如果绝对排除使用 XSLT,使用哈希表可以达到与 XSLT 键相同的效果(抱歉,不懂 PHP)。

【讨论】:

  • 是的!我喜欢你的表情,虽然它似乎并没有像你说的那样提高速度。我没有使用 xslt,但我想我现在需要了解它以及您对哈希表的建议,感谢您的回复!
  • @fclddcn:我从不觉得这个表达式很快——相反,我说它很慢,而获得更快执行速度的唯一方法是通过缓存(索引、xslt 键、哈希表,否则)。
  • 我明白了,对不起我的英语不好,我的意思是'和你说的一样':)
【解决方案2】:

从您的 XPath 开始:

 .//*[@auto and not(ancestor::*[@auto and ancestor::*[@tempId='$tempId']])]

怎么样:

 .//*[@auto and not(ancestor::*[@auto][ancestor::*[@tempId='$tempId']])]

甚至,

 .//*[@auto and count(ancestor::*[@auto][ancestor::*[@tempId='$tempId']])=0]

【讨论】:

  • 非常感谢,这教会了我一种新形式的 xpath
【解决方案3】:

我的想法是简化一点。

$path=".//*[@auto and not(ancestor::*[@auto and not(@tempId='$tempId'))]";

"祖先::*[@tempId='$tempId']"

“不(@tempId='$tempId')”


//编辑内容:消除冗长

【讨论】:

  • 非常感谢,但我认为这个和我做的不一样,不是有效的 xpath 表达式
  • 我是盲人。如果'a'有'@auto'属性的祖先,我的代码不匹配,对不起。
  • 放轻松,我在这个问题上也犯了很多错误。谢谢。
猜你喜欢
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 2010-12-17
  • 2021-11-15
  • 2020-07-01
  • 2016-07-12
相关资源
最近更新 更多