Как я могу печатать HTML с помощью Nokogiri?
Я написал веб-искателя в Ruby, и я использую Nokogiri::HTML
для разбора страницы. Мне нужно распечатать страницу и во время беспорядка в IRB я заметил метод pretty_print
. Однако он принимает параметр, и я не могу понять, что он хочет.
Мой искатель кэширует HTML-страницы веб-страниц и записывает их в файлы на моем локальном компьютере. Я хотел бы "довольно печатать" HTML, чтобы он выглядел красиво и правильно отформатирован, когда я это делаю.
Ответы
Ответ 1
Под "довольно печатной" страницей HTML я предполагаю, что вы имели в виду, что хотите переформатировать структуру HTML с правильным отступом. Нокигири этого не поддерживает; pretty_print
метод предназначен для библиотеки "pp", и вывод полезен только для отладки.
Есть несколько проектов, которые хорошо понимают HTML, чтобы иметь возможность переформатировать его, не уничтожая пробелы, которые на самом деле значительны (знаменитый HTML Tidy), но по googling я нашел этот пост под названием "Довольно печатать XHTML с помощью Nokogiri и XSLT" .
Это сводится к следующему:
xsl = Nokogiri::XSLT(File.open("pretty_print.xsl"))
html = Nokogiri(File.open("source.html"))
puts xsl.apply_to(html).to_s
Это требует от вас, конечно, загрузки связанного файла xsl в вашу файловую систему. Я пробовал это очень быстро на своей машине, и это работает как прелесть.
Ответ 2
Ответ от @mislav несколько неправильный. Nokogiri поддерживает симпатичную печать, если вы:
- Разберите документ как XML
- Поручить Nokogiri игнорировать узлы с пробелами ( "пробелы" ) во время разбора
- Используйте
to_xhtml
или to_xml
, чтобы указать параметры довольно печати
В действии:
html = '<section>
<h1>Main Section 1</h1><p>Intro</p>
<section>
<h2>Subhead 1.1</h2><p>Meat</p><p>MOAR MEAT</p>
</section><section>
<h2>Subhead 1.2</h2><p>Meat</p>
</section></section>'
require 'nokogiri'
doc = Nokogiri::XML(html,&:noblanks)
puts doc
#=> <section>
#=> <h1>Main Section 1</h1>
#=> <p>Intro</p>
#=> <section>
#=> <h2>Subhead 1.1</h2>
#=> <p>Meat</p>
#=> <p>MOAR MEAT</p>
#=> </section>
#=> <section>
#=> <h2>Subhead 1.2</h2>
#=> <p>Meat</p>
#=> </section>
#=> </section>
puts doc.to_xhtml( indent:3, indent_text:"." )
#=> <section>
#=> ...<h1>Main Section 1</h1>
#=> ...<p>Intro</p>
#=> ...<section>
#=> ......<h2>Subhead 1.1</h2>
#=> ......<p>Meat</p>
#=> ......<p>MOAR MEAT</p>
#=> ...</section>
#=> ...<section>
#=> ......<h2>Subhead 1.2</h2>
#=> ......<p>Meat</p>
#=> ...</section>
#=> </section>
Ответ 3
Вы можете попробовать REXML:
require "rexml/document"
doc = REXML::Document.new(xml)
doc.write($stdout, 2)
Ответ 4
Это сработало для меня:
pretty_html = Nokogiri::HTML(html).to_xhtml(indent: 3)
Я попробовал версию REXML выше, но это испортило некоторые мои документы. И мне не нравится приводить xslt в новый проект. Оба чувствуют усталость.:)
Ответ 5
Моим решением было добавить метод print
на фактические объекты Nokogiri
. После того, как вы выполните код в приведенном ниже фрагменте, вы должны просто написать node.print
, и он будет довольно печатать содержимое. Нет xslt требуется: -)
Nokogiri::XML::Node.class_eval do
# Print every Node by default (will be overridden by CharacterData)
define_method :should_print? do
true
end
# Duplicate this node, replace the contents of the duplicated node with a
# newline. With this content substitution, the #to_s method conveniently
# returns a string with the opening tag (e.g. `<a href="foo">`) on the first
# line and the closing tag on the second (e.g. `</a>`, provided that the
# current node is not a self-closing tag).
#
# Now, print the open tag preceded by the correct amount of indentation, then
# recursively print this node children (with extra indentation), and then
# print the close tag (if there is a closing tag)
define_method :print do |indent=0|
duplicate = self.dup
duplicate.content = "\n"
open_tag, close_tag = duplicate.to_s.split("\n")
puts (" " * indent) + open_tag
self.children.select(&:should_print?).each { |child| child.print(indent + 2) }
puts (" " * indent) + close_tag if close_tag
end
end
Nokogiri::XML::CharacterData.class_eval do
# Only print CharacterData if there non-whitespace content
define_method :should_print? do
content =~ /\S+/
end
# Replace all consecutive whitespace characters by a single space; precede the
# outut by a certain amount of indentation; print this text.
define_method :print do |indent=0|
puts (" " * indent) + to_s.strip.sub(/\s+/, ' ')
end
end
Ответ 6
Почему бы вам не попробовать метод pp
?
require 'pp'
pp some_var