Какой синтаксис xpath для получения имен тегов?

Я использую Nokogiri для анализа большого файла XML. Скажем, у меня есть следующая структура:

<menagerie>
  <penguin>Pablo</penguin>
  <penguin>Mortimer</penguin>
  <bull>Ferdinand</bull>
  <aardvark>James Cornelius Madison Humphrey Zophar Handlebrush III</aardvark>
</menagerie>

Я могу посчитать не-пингвинов так:

xml.xpath('//menagerie//*[not(penguin)]').length // 2

Но как мне получить список таких тегов? (Точный формат не важен, я просто хочу визуально отсканировать не-пингвинов.)

bull
aardvark

Обновлять

Это дало мне список, который я хотел - спасибо Oded и TMN и delnan!

xml.xpath('//menageries/*[not(penguin)]').each do |node|
  puts node.name()
end

person Nathan Long    schedule 18.01.2011    source источник
comment
Вызов xpath дает вам совпадающие элементы (я полагаю, что это какая-то коллекция). Почему вы не можете получить атрибут .tagname (или что-то подобное) каждого элемента?   -  person    schedule 18.01.2011
comment
@delnan - я не в bash, а в консоли Rails, поэтому передача через grep не работает (насколько я могу судить).   -  person Nathan Long    schedule 18.01.2011
comment
Не grep. Сбор имени тега каждого элемента. В Руби. Что-то вроде tags = xml.xpath(...).collect { |tag| tag.tagname}.   -  person    schedule 18.01.2011
comment
Вы можете сделать это короче с помощью xml.xpath(...).map(&:name) в Ruby 1.9.   -  person Phrogz    schedule 19.01.2011
comment
Обратите внимание, что это не очень похоже на Ruby - включать круглые скобки в вызов метода, когда нет параметров.   -  person Phrogz    schedule 19.01.2011
comment
@Phrogz - это необычно, но дает более четкое отладочное сообщение, поскольку теперь интерпретатор знает, что вы пытаетесь использовать метод, а не переменную.   -  person Nathan Long    schedule 01.12.2011
comment
@NathanLong FWIW, если у вас есть foo.bar, то bar всегда является вызовом метода. Но вы правильно заметили, что выполнение только bar() менее двусмысленно для интерпретатора в случае ошибки, чем bar.   -  person Phrogz    schedule 01.12.2011


Ответы (2)


Вы можете использовать ссылку name() или local-name() функция XPath.

См. примеры на zvon.

person Oded    schedule 18.01.2011
comment
Должно быть, я делаю это неправильно. xml.xpath('//meagerie/*[not(penguin)]').name() вызывает у меня ошибку неопределенного метода; то же самое для .local-name. Также пробовал с скобками: name(), local-name(). Это NoMethodError: undefined method name для #‹Nokogiri::XML::NodeSet:0x122f06c48›` - person Nathan Long; 18.01.2011
comment
Да, но я их не понимаю. Должен ли name() идти внутри xpath? Я тоже пробовал это, но получил недопустимую синтаксическую ошибку. Похоже, это не метод Нокогири. - person Nathan Long; 18.01.2011
comment
@Nathan Long - я думаю, что это должно работать: xml.xpath('name()') или xml.xpath('local-name()') - person Oded; 18.01.2011
comment
Похоже, вы получаете NodeSet обратно, вам нужно повторить его и вызвать .name() для каждого элемента. - person TMN; 18.01.2011
comment
Кажется, вы используете XPath 1.0. В XPath 2.0 выражение может возвращать последовательность строк: таким образом, Different-Values(//*/local-name()) будет возвращать отдельные имена элементов. К сожалению, XPath 1.0 может возвращать набор узлов, но только одну строку; поэтому вам придется извлекать узлы в XPath и получать их имена, используя кодирование на языке хоста. - person Michael Kay; 19.01.2011

Я знаю, что это немного устарело, но вы должны сделать: xml.xpath('//meagerie/*[not(penguin)]/name()') как выражение. Обратите внимание на косую черту, а не на точку. Вот как вы вызываете методы на текущем узле в XPath.

person bogdan.mustiata    schedule 19.11.2011