Как заменить теги, определяющие узел?

Мы пытаемся перейти от довольно маленькой системы отслеживания ошибок к Redmine. Для нашей старой системы нет готового сценария решения миграции, поэтому мы хотим сделать это сами.

Я предложил использовать Nokogiri для переноса части форматирования в новый формат (Textile), однако столкнулся с проблемами.

Это из поля БД в БД нашей старой системы:

<ul>
    <li>list item 1</li>
    <li>list item 2</li>
</ul>

Это нужно перевести в Textile, и это будет выглядеть так:

* list item 1
* list item 2

Теперь, начиная парсить с помощью Nokogiri, я здесь:

def self.handle_ul(page)
        uls = page.css("ul")
        uls.each {|ul|
                lis = ul.css("li")
                lis.each { |li|
                        li.inner_html = "*" << li.text << "\n"
                }
        }
end

Это работает как шарм. Однако мне нужно сделать две замены:

<li>
</li>

теги должны быть удалены из объекта <li>, и:

<ul>
</ul>

теги должны быть удалены из объекта <ul>. Однако я не могу найти фактические теги в объекте, представляющем его. inner_html вернул только HTML между тегами, которые я ищу:

ul.inner_html

Результат:

<li>list item 1</li>
<li>list item 2</li>

Где я могу найти теги, которые мне нужно заменить? Я думал об использовании parent и повторной связи дочерних тегов <li> с parent.parent, но это упорядочило бы их в конце прародителя.

Могу ли я как-то получить доступ ко всему HTML-представлению объекта, не удаляя его определяющие теги, чтобы я мог их заменить?


РЕДАКТИРОВАТЬ:

В соответствии с просьбой, вот макет старой записи БД и стиль, который должен быть в текстиле.

До преобразования:

Fixed for rev. 1.7.92.

<h4>Problems:</h4>
<ul>
<li>fixed.</li>
<li>fixed. New minimum 270x270</li>
<li>fixed.</li>
<li>fixed.</li>
<li>fixed.</li>
<li>fixed. Column types list is growing horizontally now.</li>
</ul>

После преобразования:

Fixed for rev. 1.7.92.

h4.Problems:
* fixed.
* fixed. New minimum 270x270
* fixed.
* fixed.
* fixed.
* fixed. Column types list is growing horizontally now.

РЕДАКТИРОВАТЬ 2:

Я попытался перезаписать части метода to_s элементов Nokogiri:

li.to_s["<li>"]=""

но это не похоже на допустимое значение lvalue (не то, чтобы это была ошибка, оно просто ничего не делает).


person 0xCAFEBABE    schedule 29.05.2013    source источник
comment
Почему вам нужна замена тега, вместо того, чтобы вы могли напрямую извлечь текст, верно? Я что-то неправильно понял?   -  person Arup Rakshit    schedule 29.05.2013
comment
Мне нужно сохранить документ в целом, изменив только определенные структуры тегов. Если бы я извлек текст, мне нужно было бы знать, где он находится в целевом документе, информация, которая была бы потеряна.   -  person 0xCAFEBABE    schedule 29.05.2013
comment
поэтому вы хотите реструктурировать существующий документ, удалив теги li и ul. Можете ли вы показать нам вывод более явным образом? после замены каким будет результирующий html?   -  person Arup Rakshit    schedule 29.05.2013
comment
Реструктуризация может быть неправильным словом. У меня есть документ в поле базы данных, которое представляет HTML. Мне нужен документ без изменений в его структуре (где находятся текстовые фрагменты), но форматирование текстовых фрагментов должно быть представлено форматированием, отличным от HTML-тегов.   -  person 0xCAFEBABE    schedule 29.05.2013
comment
хорошо! дайте этот точный ожидаемый результат, чтобы увидеть, как он выглядит.   -  person Arup Rakshit    schedule 29.05.2013
comment
вы также удалили </h4>. Это намеренно?   -  person Arup Rakshit    schedule 29.05.2013
comment
Я заменил ‹h4› на .h4, который является его текстильным эквивалентом.   -  person 0xCAFEBABE    schedule 29.05.2013


Ответы (4)


Вот основа для такого преобразования:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<ul>
    <li>list item 1</li>
    <li>list item 2</li>
</ul>
EOT
puts doc.to_html

doc.search('ul').each do |ul|
  ul.search('li').each do |li|
    li.replace("* #{ li.text.strip }")
  end
  ul.replace(ul.text)
end

puts doc.to_html

Выполнение этого вывода:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><ul>
<li>list item 1</li>
    <li>list item 2</li>
</ul></body></html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>* list item 1
    * list item 2
</body></html>

Я не собирался и не пытался сделать так, чтобы первый «элемент» имел начальный возврат каретки или перевод строки. Это остается в качестве упражнения для читателя. Я также не пытался обрабатывать теги <h4> или подобные замены. Из кода ответа вы сможете понять, как это сделать.

Кроме того, я использую Nokogiri::HTML для анализа HTML, что превращает его в полный документ HTML с соответствующим заголовком DOCTYPE, тегами <html> и <body> для имитации полного документа HTML. Вместо этого это можно было бы изменить, используя Nokogiri::HTML::DocumentFragment.parse, но на самом деле это не повлияло бы на результат.

person the Tin Man    schedule 30.05.2013
comment
Спасибо, это чрезвычайно полезно. - person 0xCAFEBABE; 31.05.2013
comment
@0xCAFEBABE Если вы сделаете это, рассмотрите возможность выпуска драгоценного камня! - person Mark Thomas; 31.05.2013

Вы можете посмотреть на ClothRed, который представляет собой конвертер HTML в Textile на Ruby. Он давно не обновлялся, но он прост и может стать хорошей отправной точкой для вашего собственного конвертера.

Если вы действительно хотите использовать Nokogiri, вы пишете фильтр, поэтому вы можете использовать интерфейс SAX.

person Mark Thomas    schedule 29.05.2013
comment
Я посмотрю, может быть, это избавит нас от проблем. Спасибо. +1 - person 0xCAFEBABE; 31.05.2013
comment
Конвертер вроде не очень. Там не происходит синтаксический анализ, он просто заменяет HTML-теги текстильными тегами. К сожалению, в настоящее время едва ли какой-либо HTML-код настолько прост. - person 0xCAFEBABE; 31.05.2013
comment
Зависит от того, что вы пытаетесь преобразовать. Если это вывод текстового редактора javascript в браузере, то он может быть достаточно последовательным, чтобы сделать это. Если это произвольный HTML, вам лучше использовать решение для синтаксического анализа, такое как ответ Железного Человека. - person Mark Thomas; 31.05.2013

Вы можете попробовать McBean (https://github.com/flavorjones/mcbean) [предупреждение: я Я автор драгоценного камня, и он давно не обновлялся].

По духу он похож на ClothRed, но внутри использует Nokogiri и фактически преобразует структуру документа в выходной текст. Он поддерживает существенное подмножество текстиля; и на самом деле я успешно использовал его для преобразования вики-страниц между вики-системами, как вы пытаетесь сделать.

person Mike Dalessio    schedule 02.06.2013

Если кому-то интересно найти это позже, другой альтернативой является использование Pandoc. Я только что сделал свои первые тесты, и этого почти достаточно, и он может работать со многими другими форматами.

person 0xCAFEBABE    schedule 03.06.2013