Подтвердить что ты не робот

Запрос пространства имен Nokogiri/Xpath

Я пытаюсь вытащить элемент 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>

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

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.

4b9b3361

Ответ 1

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

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

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

doc.remove_namespaces!
puts doc.xpath('//title')

Ответ 2

С правильно зарегистрированным префиксом 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'.

Ответ 3

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

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

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

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

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

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

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