Nokogiri оставляет объекты HTML нетронутыми

Я хочу, чтобы Nokogiri оставил нетронутыми сущности HTML, но похоже, что они преобразовывают сущности в реальный символ. Например:

 Nokogiri::HTML.fragment('<p>&reg;</p>').to_s

приводит к: "<p>®</p>"

Кажется, ничто не возвращает мне исходный HTML. Все методы .inner_html,.text,.content возвращают '®' вместо '&reg;'

Есть ли у Нокогири способ оставить эти HTML-объекты нетронутыми?

Я уже искал stackoverflow и нашел похожие вопросы, но ничего такого, как этот.

Ответы

Ответ 1

Не идеальный ответ, но вы можете заставить его сгенерировать сущности (если не красивые имена), установив разрешенную кодировку:

#encoding: UTF-8
require 'nokogiri'
html = Nokogiri::HTML.fragment('<p>&reg;</p>')
puts html.to_html                              #=> <p>®</p>
puts html.to_html( encoding:'US-ASCII' )       #=> <p>&#174;</p>

Было бы неплохо, если Нокогири использовал "хорошие" имена сущностей, которые были определены, вместо того, чтобы всегда использовать краткую шестнадцатеричную сущность, но даже это не было бы "сохранение" оригинала.

Корень проблемы состоит в том, что в HTML следующие описания описывают одно и то же содержимое:

<p>®</p>
<p>&reg;</p>
<p>&#xAE;</p>  
<p>&#174;</p>

Если вы хотите, чтобы представление to_s текста node было фактически &reg;, тогда разметка, описывающая это, действительно была бы: <p>&amp;reg;</p>.

Если Nokogiri должен всегда возвращать одну и ту же кодировку для каждого символа, которая использовалась для ввода документа, ему нужно было бы сохранить каждый символ в качестве пользовательской node записи ссылки на сущность. Существует класс, который может быть использован для этого (Nokogiri::XML::EntityReference):

require 'nokogiri'
html = Nokogiri::HTML.fragment("<p>Foo</p>")
html.at('p') << Nokogiri::XML::EntityReference.new( html.document, 'reg' )
puts html
#=> <p>Foo&reg;</p>

Однако я не могу найти способ заставить их создавать во время разбора с использованием Nokogiri v1.4.4 или v1.5.0. В частности, наличие или отсутствие Nokogiri::XML::ParseOptions::NOENT во время синтаксического разбора не создает причин для создания:

require 'nokogiri'
html = "<p>Foo&reg;</p>"
[ Nokogiri::XML::ParseOptions::NOENT,
  Nokogiri::XML::ParseOptions::DEFAULT_HTML,
  Nokogiri::XML::ParseOptions::DEFAULT_XML,
  Nokogiri::XML::ParseOptions::STRICT
].each do |parse_option|
  p Nokogiri::HTML(html,nil,'utf-8',parse_option).at('//text()')
end
#=> #<Nokogiri::XML::Text:0x810cca48 "Foo\u00AE">
#=> #<Nokogiri::XML::Text:0x810cc624 "Foo\u00AE">
#=> #<Nokogiri::XML::Text:0x810cc228 "Foo\u00AE">
#=> #<Nokogiri::XML::Text:0x810cbe04 "Foo\u00AE">