Используя Nokogiri, как преобразовать html в текст, относящийся к элементам блока (гарантируя, что они приводят к разрывам строк) - PullRequest
0 голосов
/ 30 августа 2018

Метод Nokogiri #content не преобразует блочные элементы в абзацы, например:

fragment = 'hell<span>o</span><p>world<p>I am Josh</p></p>'
Nokogiri::HTML(fragment).content
=> "helloworldI am Josh"

Я бы ожидал вывод:

=> "hello\n\nworld\n\nI am Josh"

Как преобразовать html в текст, гарантируя, что блочные элементы приводят к разрывам строк и встроенные элементы заменяются без пробелов.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Вы можете использовать #before и #after для добавления новых строк:

doc.search('p,div,br').each{ |e| e.after "\n" }
0 голосов
/ 30 августа 2018

Это мое решение:

fragment = 'hell<span>o</span><p>world<p>I am Josh</p></p>'
HtmlToText.process(fragment)
=> "hello\n\nworld\n\nI am Josh"

Я пересекаю дерево нокогири, строю текстовую строку по ходу дела, оборачиваю текст в "\n\n" для элементов блока и "" для встроенных элементов. Затем gsub, чтобы очистить изобилие \n символов в конце. Хак, но работает.

require 'nokogiri'

class HtmlToText
  class << self
    def process html
      nokogiri = Nokogiri::HTML(html)
      text = ''
      nokogiri.traverse do |el|
        if el.class == Nokogiri::XML::Element
          sep = inline_element?(el) ? "" : "\n"
          if el.children.length <= 0
            text += "#{sep}"
          else 
            text = "#{sep}#{sep}#{text}#{sep}#{sep}"
          end
        elsif el.class == Nokogiri::XML::Text
          text += el.text
        end
      end
      text.gsub(/\n{3,}/, "\n\n").gsub(/(\A\n+)|(\n+\z)/, "")
    end

    private

    def inline_element? el
      el && el.try(:name) && inline_elements.include?(el.name)
    end

    def inline_elements
      %w(
        a abbr acronym b bdo big br button cite code dfn em i img input
        kbd label map object q samp script select small span strong sub
        sup textarea time tt var
      )
    end
  end
end
...