使用Nokogiri解析HTML,并使用最接近的“"&书信电报;部门>&引用;

使用Nokogiri解析HTML,并使用最接近的“"&书信电报;部门>&引用;,html,ruby,nokogiri,Html,Ruby,Nokogiri,我的HTML包含: <div class = "s"> <p> text1 </p> <div class = "i"> <p> text2 </p> </div> </div> 这一切都很好,只是在我的数组中出现了“text2”,我不想要这些。因此,对于“text2”,最近的具有类“i”,我不希望在数组中看到它 我如何解决这个问题?可以有不同的类名和更深的嵌套,例如

我的HTML包含:

<div class = "s">
   <p> text1 </p>
   <div class = "i">
      <p> text2 </p>
   </div>
</div> 
这一切都很好,只是在我的数组中出现了
“text2”
,我不想要这些。因此,对于
“text2”
,最近的
具有类
“i”
,我不希望在数组中看到它

我如何解决这个问题?可以有不同的类名和更深的嵌套,例如:

<div class = "s">
   <p> text1 </p>
   <div class = "i">
      <p> text2 </p>
      <div class = "s">
         <p> text3 </p>
         <div class = "p">
           <p> text4 </p>
         </div>
      </div> 
   </div>
</div> 

文本1

文本2

文本3

文本4

由此,我想得到一个数组:
[“text1”,“text3”]

您可以执行以下操作:

html.css('.s > p').map {|node| node.text.strip }

这是一个更好的仅使用XPath的答案。我的原始答案如下

# Given a Nokogiri::HTML document in the `html` variable:
html.xpath("//text()[normalize-space() and ancestor::div[1][@class='s']]").map(&:text).map(&:strip)
这只会查找最近的
div
祖先具有
s
类的所有非空文本节点。这与我最初的答案是一样的,只是它完全是用XPath完成的

<div class = "s">
   <p> text1 </p>
   <div class = "i">
      <p> text2 </p>
   </div>
</div>
# => ["text1"]

<div class = "s">
   <p> text1 </p>
   <div class = "i">
      <p> text2 </p>
      <div class = "s">
         <p> text3 </p>
         <div class = "p">
           <p> text4 </p>
         </div>
      </div>
   </div>
</div>
# => ["text1", "text3"]

<div class = "s">
  <div class='p'>
    text 1
  </div>
  text 2
</div>
# => ["text 2"]
这里的基本思想是,我们找到从
div.s
派生的所有文本节点,然后为每个文本节点找到最近的
div
祖先,并且只接受具有类
s
的最近的div祖先的节点

它有点CPU密集型,但满足了严格的要求。

我从以下内容开始:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT, &:noblanks)
<div class = "s">
   <p> text1 </p>
   <div class = "i">
      <p> text2 </p>
      <div class = "s">
         <p> text3 </p>
         <div class = "p">
           <p> text4 </p>
         </div>
      </div> 
   </div>
</div> 
EOT

doc.search('.s').map{ |div| div.child.text.strip } 
# => ["text1", "text3"]
这是一个古老的逻辑:

doc.search('.s').map{ |div| div.child.text.strip } 
# => ["text1", "text3", "foobar"]
以及快速测试,以清除不需要的:

doc.search('.s').reject{ |div| div.child['class'] == 'i' }.map{ |div| div.child.text.strip } 
# => ["text1", "text3"]

如果事物是嵌套的,那么结果也将嵌套。如何编写一个更好的选择器,以右
中的
为目标,例如:
.s+p
@tadman有没有的can文本=(一个你正在处理的边缘案例的例子会有所帮助。你提供你试图解析的HTML的准确示例非常重要。不要让我们与你玩20个问题来了解真正的问题是什么,提供一个涵盖问题的最小示例。这有助于我们帮助你。所以你想要第一个非空白文本n包含在
div
?中的ode,如果文本没有或其他标记?=(
foobar
)将导致此技术失败。
require 'nokogiri'

doc = Nokogiri::XML(<<EOT, &:noblanks)
<div class = "s">
   <p> text1 </p>
   <div class = "i">
      <p> text2 </p>
      <div class = "s">
         <p> text3 </p>
         <div class = "p">
           <p> text4 </p>
         </div>
      </div> 
      <div class='s'><div class='i'>foobar</div></div>
   </div>
</div> 
EOT
doc.search('.s').map{ |div| div.child.text.strip } 
# => ["text1", "text3", "foobar"]
doc.search('.s').reject{ |div| div.child['class'] == 'i' }.map{ |div| div.child.text.strip } 
# => ["text1", "text3"]