web-dev-qa-db-de.com

Nokogiri/Xpath-Namespace-Abfrage

Ich versuche, das dc:title-Element mit einem xpath herauszuziehen. Ich kann die Metadaten mit folgendem Code abrufen.

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>

Wie Sie sehen, scheint das Obige korrekt zu funktionieren. Ich scheine jedoch nicht in der Lage zu sein, die Titelinformationen aus dieser Knotenstruktur zu erhalten. Alle unten aufgeführten schlagen fehl.

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

Könnte bitte jemand erklären, wie Namespaces in einem xpath mit dem oben genannten xml-Dokument verwendet werden sollen.

35
Jamie

Alle Namespaces müssen beim Parsen registriert werden. Nokogiri registriert automatisch Namespaces auf dem Wurzelknoten. Alle Namespaces, die sich nicht auf dem Wurzelknoten befinden, müssen Sie selbst registrieren. Das sollte funktionieren:

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

Alternativ können Sie Namespaces auch ganz entfernen. Tun Sie dies nur, wenn Sie sicher sind, dass es keine in Konflikt stehenden Knotennamen gibt.

doc.remove_namespaces!
puts doc.xpath('//title')
65
Mark Thomas

Mit dem ordnungsgemäß registrierten Präfix opf für 'http://www.idpf.org/2007/opf'-Namespace-URI und dc für 'URI' benötigen Sie:

/*/opf:metadata/dc:title

Hinweis : xmlns und xml sind reservierte Präfixe, die nicht an einen anderen Namespace-URI als den integrierten 'http://www.w3.org/2000/xmlns/' und 'http://www.w3.org/XML/1998/namespace' gebunden werden können.

1
user357812

Als Alternative zum expliziten Erstellen eines Hashes von Namespace-URIs können Sie die Namespacedefinitionen von dem XML-Element abrufen, in dem sie definiert sind.

An deinem Beispiel:

# 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)

Beachten Sie, dass der zweite xpath auch hätte sein können:

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

Aber warum von der Wurzel aus suchen, wenn Sie einen näheren Vorfahren haben? Außerdem sollten Sie das Namespace-definierende Element und dessen untergeordnete Elemente als "Gültigkeitsbereich" des Namespaces betrachten. Das Durchsuchen eines begrenzten Bereichs ist weniger verwirrend und vermeidet subtile Fehler.

0
Kelvin