Контейнерный метод в стиле Hpricot для Nokogiri? Выберите только определенные node_types

Я перемещаюсь по документу, используя селекторы CSS с Ruby, но я обнаружил некоторые ошибки селекторов css в Hpricot, которые исправлены в Nokogiri, и хочу переключиться.

Единственная проблема, с которой я столкнулся, - это выяснить, как получить массив всех дочерних элементов, которые являются "контейнерами" (т.е. не текстовыми узлами). Hpricot предоставляет эту функциональность прямо из коробки с помощью метода контейнеров.

Итак, в Hpricot я мог бы сделать:

children = doc.select('*')[0].containers

Но с Nokogiri похоже, что ту же функциональность можно получить только следующим образом (и я не уверен, работает ли она точно так же):

children = doc.css('*')[0].children.to_a.keep_if {|x| x.type != Nokogiri::XML::Node::TEXT_NODE }

Есть лучший способ сделать это?


person Sina Iman    schedule 19.04.2011    source источник


Ответы (1)


Чтобы уточнить, вам нужны только дочерние элементы, но не дочерние текстовые узлы? Если да, то вот три метода:

require 'nokogiri'
doc = Nokogiri::XML "<r>no<a1><b1/></a1><a2>no<b2>hi</b2>mom</a2>no</r>"

# If the element is uniquely selectable via CSS
kids1 = doc.css('r > *')

# ...or if we assume you found an element and want only its children
some_node = doc.at('r')

# One way to do it
kids2 = some_node.children.grep(Nokogiri::XML::Element)

# A geekier-but-shorter-way
kids3 = some_node.xpath('*')

# Confirm that they're the same (converting the NodeSets to arrays)
p [ kids1.to_a == kids2, kids2 == kids3.to_a ]
#=> [true, true]

p kids1.map(&:name), kids2.map(&:name), kids3.map(&:name)
#=> ["a1", "a2"]
#=> ["a1", "a2"]
#=> ["a1", "a2"]
person Phrogz    schedule 21.04.2011
comment
Это здорово, именно то, что я искал. Я определенно буду использовать более короткую (гиковскую? :P) версию, очень чистую. - person Sina Iman; 24.04.2011