Запрос пространства имен Nokogiri / Xpath - PullRequest
35 голосов
/ 14 января 2011

Я пытаюсь извлечь элемент dc:title, используя xpath. Я могу извлечь метаданные, используя следующий код.

doc = <<END
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0">
  <metadata xmlns:dc="URI">
    <dc:title>title text</dc:title>
  </metadata>
</package>
END

doc = Nokogiri::XML(doc)

# Awesome this works!
puts '//xmlns:metadata'
puts doc.xpath('//xmlns:metadata')
# => <metadata xmlns:dc="URI"><dc:title>title text</dc:title></metadata>

Как вы можете видеть выше, похоже, работает правильно. Однако мне кажется, что я не могу получить информацию о заголовке из этого дерева узлов, все нижеприведенное не работает.

puts doc.xpath('//xmlns:metadata/title')
# => nil

puts doc.xpath('//xmlns:metadata/dc:title')
# => ERROR: `evaluate': Undefined namespace prefix

puts doc.xpath('//xmlns:dc:title')
# => ERROR: 'evaluate': Invalid expression: //xmlns:dc:title

Может кто-нибудь объяснить, как пространства имен должны использоваться в xpath с указанным выше документом xml.

Ответы [ 3 ]

66 голосов
/ 14 января 2011

Все пространства имен должны быть зарегистрированы при разборе. Nokogiri автоматически регистрирует пространства имен в корневом узле. Любые пространства имен, которые не находятся на корневом узле, вы должны зарегистрировать самостоятельно. Это должно работать:

puts doc.xpath('//dc:title', 'dc' => "URI")

Кроме того, вы можете полностью удалить пространства имен. Делайте это только в том случае, если вы уверены, что не будет конфликтующих имен узлов.

doc.remove_namespaces!
puts doc.xpath('//title')
1 голос
/ 14 января 2011

С правильно зарегистрированным префиксом opf для 'http://www.idpf.org/2007/opf' URI пространства имен и dc для 'URI' вам необходимо:

/*/opf:metadata/dc:title

Примечание : xmlns и xml являются зарезервированными префиксами, которые нельзя привязать к любому другому URI пространства имен, кроме встроенных 'http://www.w3.org/2000/xmlns/' и 'http://www.w3.org/XML/1998/namespace'.

0 голосов
/ 28 июля 2016

В качестве альтернативы явному построению хэша URI пространства имен вы можете получить определения пространства имен из элемента xml, где они определены.

Используя ваш пример:

# First grab the metadata node, because that's where "dc" is defined.
metadata = doc.at_xpath('//xmlns:metadata')

# Pass metadata's namespaces as the resolver.
metadata.at_xpath('dc:title', metadata.namespaces)

Обратите внимание, что второй xpath также мог быть:

doc.at_xpath('//dc:title', metadata.namespaces).to_s

Но зачем искать в корне, если у вас есть более близкий предок?Кроме того, вы должны рассматривать элемент, определяющий пространство имен, плюс его дочерние элементы как «область» пространства имен.Поиск в ограниченной области менее запутан и позволяет избежать мелких ошибок.

...