将XPath与HTML或XML片段一起使用?

时间:2010-09-28 23:50:42

标签: ruby xpath nokogiri

我是Nokogiri和XPath的新手,我正在尝试访问HTML或XML片段中的所有注释。 当我不使用.//comment()函数时,XPath //comment()fragment可以正常工作,但它们找不到任何带有片段的内容。使用标记而不是注释,它适用于第一个XPath。

通过反复试验,我意识到在这种情况下,comment()只找到顶级评论和.//comment(),其他一些只发现内部评论。难道我做错了什么?我错过了什么?谁能解释一下发生了什么?

我应该使用什么XPath来获取Nokogiri解析的HTML片段中的所有注释?

此示例有助于理解问题:

str = "<!-- one --><p><!-- two --></p>"

# this works:
Nokogiri::HTML(str).xpath("//comment()")
=> [#<Nokogiri::XML::Comment:0x3f8535d71d5c " one ">, #<Nokogiri::XML::Comment:0x3f8535d71cf8 " two ">]
Nokogiri::HTML(str).xpath(".//comment()")
=> [#<Nokogiri::XML::Comment:0x3f8535cc7974 " one ">, #<Nokogiri::XML::Comment:0x3f8535cc7884 " two ">]

# with fragment, it does not work:
Nokogiri::HTML.fragment(str).xpath("//comment()")
=> []
Nokogiri::HTML.fragment(str).xpath("comment()")
=> [#<Nokogiri::XML::Comment:0x3f8535d681a8 " one ">]
Nokogiri::HTML.fragment(str).xpath(".//comment()")
=> [#<Nokogiri::XML::Comment:0x3f8535d624d8 " two ">]
Nokogiri::HTML.fragment(str).xpath("*//comment()")
=> [#<Nokogiri::XML::Comment:0x3f8535d5cb8c " two ">]
Nokogiri::HTML.fragment(str).xpath("*/comment()")
=> [#<Nokogiri::XML::Comment:0x3f8535d4e104 " two ">]

# however it does if it is a tag instead of a comment:
str = "<a desc='one'/> <p><a>two</a><a desc='three'/></p>"
Nokogiri::HTML.fragment(str).xpath(".//a")
=> [#<Nokogiri::XML::Element:0x3f8535cb44c8 name="a" attributes=[#<Nokogiri::XML::Attr:0x3f8535cb4194 name="desc" value="one">]>, #<Nokogiri::XML::Element:0x3f8535cb4220 name="a" children=[#<Nokogiri::XML::Text:0x3f8535cb3ba4 "two">]>, #<Nokogiri::XML::Element:0x3f8535cb3a3c name="a" attributes=[#<Nokogiri::XML::Attr:0x3f8535cb3960 name="desc" value="three">]>]

PS:没有fragment它会做我想要的,但它也添加了一些像“DOCTYPE”的东西,我真的只有一个我正在编辑的HTML文件的片段(删除一些标签,替换其他标签)

2 个答案:

答案 0 :(得分:7)

//comment()/descendant-or-self::node()/child::comment()

的缩写形式

将此xpath与片段一起使用会忽略根注释(它们由/descendant-or-self::node()选中,但它们没有子项)。

如果使用HTML(str),则创建文档节点作为所有其他项的根。因此,/descendant-or-self::node()/child::comment()不会忽略顶级注释,因为它们是文档节点的子节点(它本身由/descendant-or-self::node()选择)。

我不确定为什么descendant::comment()在任何情况下都有效,我会说它应该是descendant-or-self::comment(),但不要介意。

希望有帮助吗?

答案 1 :(得分:3)

"descendant::comment()""descendant::sometag"在每种情况下均可正常使用,但我仍然不理解这些差异。