【问题标题】:Use Nokogiri to select all <span> tags between a random selection of <br> tags使用 Nokogiri 在随机选择的 <br> 标签之间选择所有 <span> 标签
【发布时间】:2012-09-28 08:58:40
【问题描述】:

我正在尝试使用 Nokogiri 和 Ruby 解析一些 HTML,但在做我想做的事情时遇到了一些麻烦。我的示例文件如下所示:

<div id="main-body">
  <p>
    <span>First Text</span>
    <span>Second Text</span>
    <span>Third Text</span>
    <span>Fourth Text</span>
    <br>
    <span>Fifth Text</span>
    <span>Sixth Text</span>
    <span>Seventh Text</span>
    <br>
    <span>Eight Text</span>
    <span>Ninth Text</span>
    <br>
  </p>
</div

我正在尝试找到一种方法来遍历并仅选择随机中断标记之间或第一次中断之前的文本。

基本上我想让我的输出每次都不同。所以示例输出将是例如

=>First Text
=>Second Text
=>Third Text
=>Fourth Text

那么一次,也许下一次它会在休息 2 和 3 之间得到东西

=>Eight Text
=>Ninth Text

我在想,如果我可以计算 HTML 中的中断数,我可以使用 rand() 随机选择一个并打印出文本,直到我点击下一个,但我无法完全理解正确。

到目前为止,我的代码是将整个页面加载到 Nokogiri 类型并尝试从那里解析。

doc = Nokogiri::HTML(open(targeturl))
puts doc.xpath("./br").length #gives me the count of break tags in the document

从那里我实际上可以将中断分配给一个变量并逐个访问它们,但我不知道该去哪里,或者我什至从这里走在正确的轨道上,我觉得我只是感到困惑我自己在这一点上:/

【问题讨论】:

    标签: ruby xpath nokogiri


    【解决方案1】:

    您可以使用count()和preceding-sibling根据前面的br标签数量来抓取节点。

    puts doc.xpath("//span[count(preceding-sibling::br)=0]")
    #=> <span>First Text</span>
    #=> <span>Second Text</span>
    #=> <span>Third Text</span>
    #=> <span>Fourth Text</span>
    
    puts doc.xpath("//span[count(preceding-sibling::br)=1]")
    #=> <span>Fifth Text</span>
    #=> <span>Sixth Text</span>
    #=> <span>Seventh Text</span>
    
    puts doc.xpath("//span[count(preceding-sibling::br)=2]")
    #=> <span>Eight Text</span>
    #=> <span>Ninth Text</span>
    

    要获得随机选择,只需随机化前兄弟的数量:

    puts doc.xpath("//span[count(preceding-sibling::br)=#{rand(doc.xpath("//br").length)}]")
    

    【讨论】:

      【解决方案2】:

      还有一个选项是 slice_before:

      doc.search('p *').slice_before{|x| x.name == 'br'}.each do |slice|
        puts '*', slice.select{|x| x.name == 'span'}
      end
      

      【讨论】:

        【解决方案3】:

        这是我的解决方案,如果你只想要span元素的内容(要获取整个节点,只需删除map操作):

        require 'nokogiri'
        
        doc = Nokogiri::XML(File.read("test.xml"))
        
        def get_spans(doc)
            br_list = doc.css("br")
            br = br_list[rand(br_list.size)]
        
            span_list = []
            span = br.previous_element
        
            while span && span.name == "span"
                 span_list << span
                 span = span.previous_element
            end
        
            span_list.reverse.map(&:content)
        end
        
        p get_spans(doc)
        

        【讨论】:

          【解决方案4】:

          这是一个单一的 XPath 单行表达式,它选择 $k-th br 之前的所有文本节点,但不选择 $k-1th br 之前的所有文本节点:

          /*/p/br[2]/preceding-sibling::*[count(preceding-sibling::br)=1]/text()
          

          因此,如果您在区间 [1, count(/*/p/br)] 中有一个随机的 k,那么您只需将其替换为上述 Xpath 表达式并对其求值。

          基于 XSLT 的验证:

          <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
           <xsl:output  method="text"/>
          
           <xsl:template match="/">
               <xsl:copy-of select=
               "/*/p/br[2]/preceding-sibling::*[count(preceding-sibling::br)=1]/text()
               "/>
           </xsl:template>
          </xsl:stylesheet>
          

          当此转换应用于提供的 XML 文档时:

          <div id="main-body">
              <p>
                  <span>First Text</span>
                  <span>Second Text</span>
                  <span>Third Text</span>
                  <span>Fourth Text</span>
                  <br/>
                  <span>Fifth Text</span>
                  <span>Sixth Text</span>
                  <span>Seventh Text</span>
                  <br/>
                  <span>Eight Text</span>
                  <span>Ninth Text</span>
                  <br/>
              </p>
          </div>
          

          计算 XPath 表达式,并将计算结果(所有选定的文本节点)复制到输出:

          Fifth TextSixth TextSeventh Text
          

          【讨论】:

            猜你喜欢
            • 2014-09-28
            • 1970-01-01
            • 1970-01-01
            • 2016-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-02-06
            相关资源
            最近更新 更多