【问题标题】:Using XPath with HTML or XML fragment?将 XPath 与 HTML 或 XML 片段一起使用?
【发布时间】:2010-09-28 23:50:42
【问题描述】:

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

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

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

这个例子可以帮助理解问题:

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 文件的片段(删除一些标签,替换其他标签)。

【问题讨论】:

    标签: ruby xpath nokogiri


    【解决方案1】:

    //comment()/descendant-or-self::node()/child::comment() 的简写形式

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

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

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

    希望有帮助吗?

    【讨论】:

    • 是的,这有帮助!谢谢!我不太明白self(上下文节点)是什么。 descendant-or-selfdescendant 相同,但也包括上下文节点。我试过只在字符串中添加一个注释 (str = '&lt;!-- foobar --&gt;'),即使在这种情况下,它也是一个后代,并且只有 descendant::comment() 有效。
    【解决方案2】:

    "descendant::comment()""descendant::sometag" 在每种情况下都可以正常工作,但我仍然不明白这些差异。

    【讨论】:

      猜你喜欢
      • 2014-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 2011-06-14
      相关资源
      最近更新 更多