Преобразователи IMO не предназначены для извлечения данных, таких как:
Преобразователи позволяют вам фильтровать и изменять узлы, используя собственную собственную логику [...]
Это не то, что вы пытаетесь сделать;Вы пытаетесь извлечь данные из узлов и преобразовать их.В вашем примере вы не делаете одно и то же для каждого элемента: иногда вы добавляете запятую, иногда добавляете запятую и слово «и».
Чтобы сделать это, вам нужно либочтобы сохранить состояние и последующую обработку, или заглянуть в поток узлов, чтобы увидеть, посещаете ли вы последний узел.Я не знаю тривиального способа сделать это с помощью преобразователей Sanitize, поэтому этот пример сохраняет состояние и пост-процессы.
require 'sanitize'
items = []
s = "<ul><li>some space</li><li>more stuff with spaces</li><li>last one</li></ul>"
save_li = lambda do |env|
node = env[:node]
items << node.text.strip if node.text?
end
Sanitize.clean(s, :transformers => save_li)
# => " some space more stuff with spaces last one "
output = "#{items[0..-2].join(", ")}, and #{items[-1]}"
# => "some space, more stuff with spaces, and last one"
IMO этот пример - злоупотребление преобразователями, потому что он запускается только из-за его побочного эффекта, он ничего не делает, кроме как ищет текстовые узлы.
Если один из элементов списка имеет встроенный HTML, наивный подход больше не работает, и вам нужно начать знать больше Nokogiriв любом случае:
items = []
s = "<ul><li>some space</li><li>item <b>with<b/> html</li><li>c</li></ul>"
save_li = lambda do |env|
node = env[:node]
items << node.content if node.name == "li"
end
Sanitize.clean(s, :transformers => save_li)
# => " some space item with html c "
output = "#{items[0..-2].join(", ")}, and #{items[-1]}"
# => "some space, item with html, and c"
Этот подход основан на стандартном поведении Sanitize, когда ничто не занесено в белый список.Теги <b>
все еще посещаются лямбдой save_li
, но они очищаются.Это может вызвать проблемы при различных обстоятельствах.