J'essaie d'extraire l'élément dc:title
en utilisant un xpath. Je peux extraire les métadonnées en utilisant le code suivant.
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>
Comme vous pouvez le constater, ce qui précède semble fonctionner correctement. Cependant, il semble que je ne puisse pas obtenir les informations de titre de cette arborescence de noeuds, tous les éléments ci-dessous échouent.
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
Quelqu'un pourrait-il s'il vous plaît expliquer comment les espaces de noms doivent être utilisés dans un xpath avec le doc xml ci-dessus.
Tous les espaces de noms doivent être enregistrés lors de l'analyse. Nokogiri enregistre automatiquement les espaces de noms sur le nœud racine. Tous les espaces de noms qui ne sont pas sur le nœud racine doivent être enregistrés par vous-même. Cela devrait fonctionner:
puts doc.xpath('//dc:title', 'dc' => "URI")
Alternativement, vous pouvez supprimer complètement les espaces de noms. Ne le faites que si vous êtes certain qu'il n'y aura pas de noms de nœuds en conflit.
doc.remove_namespaces!
puts doc.xpath('//title')
Avec le préfixe correctement enregistré opf
pour 'http://www.idpf.org/2007/opf'
URI d'espace de nom et dc
pour 'URI'
, vous avez besoin des éléments suivants:
/*/opf:metadata/dc:title
Remarque : xmlns
et xml
sont des préfixes réservés qui ne peuvent être liés à aucun autre URI d'espace de nom que les 'http://www.w3.org/2000/xmlns/'
et 'http://www.w3.org/XML/1998/namespace'
intégrés.
Au lieu de créer explicitement un hachage d'URI d'espace de nom, vous pouvez récupérer les définitions d'espace de nom à partir de l'élément xml où elles ont été définies.
En utilisant votre exemple:
# 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)
Notez que le second xpath aurait aussi pu être:
doc.at_xpath('//dc:title', metadata.namespaces).to_s
Mais pourquoi chercher à la racine quand vous avez un ancêtre plus proche? En outre, vous devez considérer l'élément définissant l'espace de nom, ainsi que ses enfants, comme la "portée" de l'espace de nom. Rechercher dans un champ limité est moins déroutant et évite les bugs subtils.