Удалите все теги в XML-документе, кроме определенных, с помощью Ruby

#ruby #xml #nokogiri

#ruby #xml #nokogiri

Вопрос:

 require 'nokogiri'

doc = Nokogiri::XML "<root>
    <a>foo<c>bar</c></a>
  <b>jim<d>jam></d></b>
  <a>more</a>
  <x>no no no</x>
</root>"

doc.css("a, b").each {|o| p o.to_s}
# "<a>foo<c>bar</c></a>"
# "<a>more</a>"
# "<b>jim<d>jamamp;></d></b>"
  

Как я могу сохранить теги в их первоначальном порядке? Или также удалить вложенные теги?

Ответ №1:

Возможно, вы захотите посмотреть на белый список / blacklist / scrubbing gems. На ум приходят дезинфекция и мочалка.

Из описания Sanitize:

Учитывая список допустимых элементов и атрибутов, Sanitize удалит весь неприемлемый HTML из строки.

Из описания люфы:

Loofah превосходно очищает HTML (предотвращение XSS). Он включает в себя несколько хороших средств очистки HTML, которые основаны на белом списке HTML5lib, поэтому, скорее всего, это не сделает ваши коды менее безопасными. (Эти инструкции не были оценены Netexperts.)

В любом случае, они избавят вас от необходимости изобретать велосипед.

Ответ №2:

 require 'nokogiri'
doc = Nokogiri::XML "
<root>
  <a>foo<c>bar</c></a>
  <b>jim<d>jam></d></b>
  <a>more</a>
  <x>no no no</x>
</root>"

doc.xpath('root//*[name()!="a"][name()!="b"]').remove
puts doc
#=> <?xml version="1.0"?>
#=> <root>
#=>   <a>foo</a>
#=>   <b>jim</b>
#=>   <a>more</a>
#=>   
#=> </root>
  

Ответ №3:

Если это просто проблема порядка, и ни один из тегов, которые вам нужно изолировать, не является вложенным, использование XPath вместо CSS-селекторов в Nokogiri должно возвращать теги в том же порядке, в котором они находятся в документе:

 doc.xpath("//a | //h3").each { |o| puts o }
  

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

Конечно, если нужные вам теги когда-либо являются вложенными, вам может потребоваться определить, что означает «удалить все теги, кроме определенных» (например, что происходит с удаленными тегами и их содержимым, которые существуют внутри не удаленных тегов и их содержимого и т.д.).

Если ваше требование достаточно сложное, так что запросы XPath не будут его выполнять, вам может потребоваться «обойти DOM», используя что-то вроде doc.root.children и рекурсивно проверить дочерние элементы каждого узла.