Следующий код обезьяны-патчи Nokogiri::XML::Node
для удовольствия, но, конечно, вы можете извлечь их как отдельные методы, берущих аргумент узла, если тебе нравится. (Только метод height
является частью вашего вопроса, но я думал, что метод deepest_leaves
может быть интересно.)
require 'nokogiri'
class Nokogiri::XML::Node
def depth
ancestors.size
# The following is ~10x slower: xpath('count(ancestor::node())').to_i
end
def leaves
xpath('.//*[not(*)]').to_a
end
def height
tallest = leaves.map{ |leaf| leaf.depth }.max
tallest ? tallest - depth : 0
end
def deepest_leaves
by_height = leaves.group_by{ |leaf| leaf.depth }
by_height[ by_height.keys.max ]
end
end
doc = Nokogiri::XML "<root>
<a1>
<b1></b1>
<b2><c1><d1 /><d2><e1 /><e2 /></d2></c1><c2><d3><e3/></d3></c2></b2>
</a1>
<a2><b><c><d><e><f /></e></d></c></b></a2>
</root>"
a1 = doc.at_xpath('//a1')
p a1.height #=> 4
p a1.deepest_leaves.map(&:name) #=> ["e1", "e2", "e3"]
p a1.leaves.map(&:name) #=> ["b1", "d1", "e1", "e2", "e3"]
Редактировать: Для того, чтобы ответить только задал вопрос односложно, без упаковки его в ре неиспользованные детали:
p a1.xpath('.//*[not(*)]').map{ |n| n.ancestors.size }.max - a1.ancestors.size
Хороший вопрос, +1. См. Мой ответ для описания решения на основе XPath 1.0 и решения с одним XPath-2.0-выражением. –
Связанный: [Как выбрать все листовые узлы с использованием выражения XPath?] (Http://stackoverflow.com/questions/3926589/how-to-select-all-leaf-nodes-using-xpath-expression) – Phrogz