没有具有相同属性的祖先的属性的xPath表达式

时间:2011-02-27 08:16:32

标签: ruby xpath

我正在尝试使用属性提取元素,而不是分别提取具有相同属性的后代。

使用以下html:

<html><body>
  <div box>
    some text
    <div box>
      some more text
    </div>
  </div>
  <div box>
    this needs to be included as well
  </div>
</body></html>

我希望能够提取两个外部<div box>及其后代,包括内部<div box>,但不希望单独提取内部<div box>

我尝试过使用各种不同的表达方式但认为我遗漏了一些非常基本的东西。我一直在尝试的主要表达方式是://[@box and not(ancestor::@box)但这仍然会返回两个元素。

我试图使用Ruby 1.9.2中的'Hpricot'(0.8.3)Gem执行此操作,如下所示:

# Assuming html is set to the html above
doc = Hpricot(html)
elements = doc.search('//[@box and not(ancestor::@box)]')

# The following is returning 3 instead of 2
elements.size

对此的任何帮助都会很棒。

2 个答案:

答案 0 :(得分:2)

您的XPATH无效。您必须解决某些问题才能使用谓词过滤器(例如[])。否则,没有任何东西可以过滤。

此XPATH有效:

//div[@box and not(ancestor::div/@box)]

如果元素并非全部保证为<div>,则可以对元素使用更通用的匹配:

//*[@box and not(ancestor::*/@box)]

答案 1 :(得分:0)

使用elements = doc.search('//[@box and not(ancestor::@box)]')不正确。

使用会发现第一次出现的elements = doc.at('//div[@box]')

我建议使用Nokogiri而不是Hpricot。 Nokogiri得到了很好的支持,非常灵活和强大。


编辑:已添加,因为原始问题已更改:

  

非常感谢,但我忘了提到我想要返回多个外部元素。对不起,我已经更新了这个问题。我会进一步研究Nokogiri,我最初没有选择它,因为Hpricot似乎更平易近人。

请记住,XPath的作用类似于以最简单的形式访问目录中的文件,因此您可以向下钻取并搜索“子目录”。如果您只想要外部<div>标记,请查看<body>级别内部,不再进一步:

doc.search('/html/body/div')

或者,如果您的目标可能包含未经修饰的div标记:

doc.search('/html/body/div[@box]')

关于Hpricot似乎更平易近人:

Nokogiri实现了Hpricot访问器的超集,允许您将其放置到适合大多数用途的位置。它支持XPath和CSS访问器,如果您使用CSS和HTML并且不需要XPath,则可以使用更直观的方式获取数据。此外,有许多方法可以找到您想要的目标:

doc.search('body > div[box]')
(doc / 'body > div[box]')
doc.css('body > div[box]')

Nokogiri支持在Hpricot中找到的at%同义词以及css_at,如果您只想要第一次出现的话。

在遇到Hpricot爆炸的某些情况后,我开始使用Nokogiri,因为它无法在荒野中处理格式错误的新闻。