Как рассчитать количество «уровней» потомков узла Нокогири? - PullRequest
4 голосов
/ 17 апреля 2011

Вы можете позвонить Nokogiri::XML::Node#ancestors.size, чтобы увидеть, насколько глубоко вложен узел.Но есть ли способ определить, насколько глубоко вложенным является самый глубоко вложенный дочерний элемент узла?

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

Ответы [ 2 ]

1 голос
/ 18 апреля 2011

Следующий код monkey-patches 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 голос
/ 17 апреля 2011

Вы можете позвонить Nokogiri :: XML :: Node # ancestors.size to Посмотрите, как глубоко узел вложен. Но Есть ли способ определить, насколько глубоко вложенный самый глубоко вложенный ребенок узел есть?

Используйте

count(ancestor::node())

Это выражение выражает количество предков, которые контекстный (текущий) узел имеет в иерархии документов.

Чтобы найти уровень вложенности «самого глубоко вложенного потомка», необходимо сначала определить все «листовые» узлы:

descendant-or-self::node()[not(node())]

и для каждого из них получите свой уровень вложенности, используя приведенное выше выражение XPath.

Затем должен быть рассчитан максимальный уровень вложенности (максимум всех произведенных чисел), и этот последний расчет невозможен для чистого XPath 1.0 .

Это можно выразить в одном выражении XPath 2.0:

max(for $leaf in /descendant-or-self::node()[not(node())],
        $depth in count($leaf/ancestor::node())
      return
        $depth
    )
...