XPath用于查找带有文本的节点+所有后代&符合某些标准的兄弟姐妹

时间:2011-09-23 14:26:39

标签: javascript html xpath greasemonkey

背景
我正在努力改进我发现的Greasemonkey script 该脚本标记外币价格,并可将其转换为您选择的货币。

主要问题:
如何在使用标记列出价格时处理脚本,例如:

<b><i>9.</i></b><sup>95</sup>EUR

(例如,Newegg.com这样做 - 他们写下这样的价格:&lt; span&gt; $&lt; / span&gt; 174&lt; sup&gt; .99&lt; / sup&gt;)。

目前,该脚本仅查找自使用的XPath表达式以来在同一文本节点中列出的价格:

document.evaluate("//text()", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)

由于脚本需要很快,我试图避免过多地使用DOM ...
是否有任何XPath专家可以为此目的提供一些智能解决方案?

问题的更详细说明:
我现在用于查找文本节点的代码:

var re_skip = /^(SCRIPT|IFRAME|TEXTAREA|STYLE|OPTION|TITLE|HEAD|NOSCRIPT)$/;  // List of elements whose text node-children can be skipped
text = document.evaluate("//text()", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var i = text.snapshotLength;
while (i--) {
    el = text.snapshotItem(i);
    if (!el.parentNode || re_skip.test(el.parentNode.nodeName.toUpperCase()) || el.parentNode.className == 'autocurrency') {
        continue;
    }
//  ...
//  (RegEx logic to check if prices can be found in the text)
}


  • 放弃其元素在“re_skip”中列出的文本节点的检查也可以在XPath表达式中完成(using the "not" notation),对吗?这会增加速度吗?

  • 如果使用了有序的XPath类型,我想我不再需要检查是否正在解析的文本节点的父节点是&lt; span class =“autocurrency”&gt; (即脚本在匹配的价格附近添加的&lt; span&gt;)。

  • 如果我理解正确的话,normalize-space()(如建议的here)在这种情况下不能使用,因为脚本添加了&lt; span class =“autocurrency”&gt ;在匹配金额附近,我们需要为此&lt; span&gt;的位置保留正确的索引。应该输入。

  • XPath是否允许在货币值之间仅使用某些(内联)元素?或者也许它可以这样做:“当找到包含文本的节点时,还包括匹配中的所有子节点(及其子节点等) - 除非子节点是块类型元素。“ (或者它应该读作:“......除非子节点是DIV,P,TABLE或re_skip中的任何元素”)

我可以重写正则表达式以处理诸如“&lt; span&gt; $&lt; / span&gt; 174&lt; sup&gt; .99&lt; / sup&gt;”之类的文字只要我找到这些文本字符串 - 最好使用XPath,因为我已经明白这比步进DOM更快。

非常感谢你提前给我任何帮助!  
----------------------------------------------- ---------------
修改
好的,我现在意识到这个问题可以通过一些澄清和一些例子来做,所以他们来了。网页可能如下所示:

<body>
  <div>
    <span>9.95 <span>EUR</span></span><br />
    <span>8.<sup>95</sup></span>AU$<br />
    <table>
      <thead>
        <tr>
          <th>Bla</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><b>7</b>.95kr</td>
        </tr>
      </tbody>
    </table>
    <div>Bla bla</div>
    6.95 <span>GBP</span>
  </div>
  <div><img src="" /><img src=""><span>Bla bla bla</span></div>
</body>

现在,在那个例子中,开销并不是那么好 - 我可以直接将整个源代码作为字符串提供给找到价格的正则表达式。但通常情况下,如果我没有使用快速XPath来解析文本,页面将有很多非文本元素会使脚本变得非常慢。所以,我正在寻找一个XPath表达式,它可以在上面的例子中找到不同的文本,但不是只是文本内容 - 因为我们还需要可能包围的标签价格的一部分(稍后将在匹配的价格周围创建一个新的&lt; span&gt;,包括可能包含部分价格的任何内联元素)。

我不确切知道XPath可以返回什么,但是以某种方式我需要抓住上面示例页面中的以下字符串:

"9.95 <span>EUR</span>"       (or possibly: "<span>9.95 <span>EUR</span></span>")
"<span>8.<sup>95</sup></span>AU$"
"Bla"                         (or possibly: "<th>Bla</th>")
"<b>7</b>.95kr"               (or possibly: "<td><b>7</b>.95kr</td>")
"Bla bla"                     (or possibly: "<div>Bla bla</div>")
"6.95 <span>GBP</span>"
"Bla bla bla"                 (or possibly: "<span>Bla bla bla</span>")

然后这些字符串可以由找到价格的正则表达式解析。

1 个答案:

答案 0 :(得分:1)

你当然可以使用像//*[not(self::script | self::textarea | self::style)]//text()这样的路径来查找那些不是“script”,“textarea”,“style”之一的元素节点的文本节点后代。所以你没有必要进行正则表达式测试,你可以用XPath表达这个要求。无论性能是否更好我都说不清楚,您必须检查要使用Greasemonkey脚本的浏览器的XPath实现。