2014-09-16 2 views
1

Я пытаюсь очистить CMS, введенный в HTML, который имеет посторонние теги абзацев и теги br везде. Жесткость Sanitize оказалась очень полезной для этого, но я застрял в особой проблеме.Sanitizing HTML с помощью Nokogiri

Проблема заключается в том, когда есть уш тег непосредственно после/до пункта тег, например

<p> 
    <br /> 
    Some text here 
    <br /> 
    Some more text 
    <br /> 
</p> 

Я хотел бы вычистить посторонние первые и последний BR тег, но не средний.

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

Любая помощь будет высоко оценена.

+0

Я не знаком с дезинфицировать, но '/
(. *)
/'будет соответствовать средней части без ведущих тэгов'
'. – engineersmnky

+1

Не используйте регулярное выражение для управления HTML. Это слишком хрупкое решение. –

+0

И вам действительно нужно показать нам, что вы пробовали. Это позволяет нам знать, что вы хотите знать, как ловить рыбу, а не просто просить об этом. –

ответ

1

Вот как найти конкретные <br> узлы, содержащиеся <p>:

require 'nokogiri' 

doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT) 
<p> 
    <br /> 
    Some text here 
    <br /> 
    Some more text 
    <br /> 
</p> 
EOT 

doc.search('p > br').map(&:to_html) 
# => ["<br>", "<br>", "<br>"] 

После того, как мы знаем, что можем их найти, легко удалить отдельные из них:

br_nodes = doc.search('p > br') 
br_nodes.first.remove 
br_nodes.last.remove 
doc.to_html 
# => "<p>\n \n Some text here\n <br>\n Some more text\n \n</p>\n" 

Обратите внимание, что Nokogiri удалили их, но их связанные текстовые узлы, являющиеся их непосредственными братьями и сестрами, содержащие их «\ n», остались позади. Браузер будет пожирать тех, кто и не отображать строки-эндов, но вы могли бы чувствовать OCD, так вот, как удалить те же:

br_nodes = doc.search('p > br') 
[br_nodes.first, br_nodes.last].each do |br| 
    br.next_sibling.remove 
    br.remove 
end 
doc.to_html 
# => "<p>\n <br>\n Some more text\n </p>\n" 
+0

Привет, оловянный человек - большое спасибо за вашу помощь, в конце концов мне удалось получить рабочую версию, продолжающую подход, который я принимал, - я разместил его здесь, чтобы вы могли видеть, что мне удалось поймать рыбу самостоятельно, но теперь можно улучшить моя техника благодаря совету более опытного рыболова :) – Chris

0
initial_linebreak_transformer = lambda {|options| 
    node = options[:node] 
    if node.present? && node.element? && node.name.downcase == 'p' 
    first_child = node.children.first 
    if first_child.name.downcase == 'br' 
     first_child.unlink 
     initial_linebreak_transformer.call options 
    end 
    end 
} 
+0

Похоже, вы делаете это медленнее и сложнее. Вместо того, чтобы проверять, присутствует ли узел, это элемент, а его имя - '' p'', сообщите Nokogiri о поиске узлов с помощью селектора CSS или XPath; В этот момент вы ЗНАЕТЕ все эти вещи и можете просто делать то, что хотите с этим узлом. Это намного быстрее, чтобы позволить libXML сделать это, чем итеративно делать это для каждого узла. Я настоятельно рекомендую тестировать тесты, чтобы доказать/опровергнуть ваш текущий метод, поскольку большой или сложный HTML-документ будет дорогостоящим процессом. –

+0

Еще раз спасибо - я обязательно попробую ваш подход в предпочтении. Я получил основание из этого: https://github.com/vjt/sanitize-rails/blob/master/example/sanitizer.rb#L22-L27, поскольку я использую дезинфицирующее средство, и это был самый подходящий код, который я нашел для начала найти способ получить результат, который я хотел. Полностью согласен, что лучше использовать libXML. Надеюсь, что это имеет смысл и еще раз спасибо за ваш совет. – Chris

Смежные вопросы