2011-01-14 14 views
32

Próbuję wyciągnąć element dc:title przy użyciu xpath. Mogę wyciągnąć metadane za pomocą następującego kodu.Kwerenda nazw Nokogiri/Xpath zapytanie

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> 

Jak widać powyższe wydaje się działać poprawnie. Jednak wydaje mi się, że nie mogę uzyskać informacji o tytule z tego drzewa węzłów, wszystkie poniższe niszczą.

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 

Czy mógłby ktoś wyjaśnić, jak należy używać przestrzeni nazw w ścieżce xpath z powyższym dokumentem xml.

Odpowiedz

60

Wszystkie przestrzenie nazw należy zarejestrować podczas analizy. Nokogiri automatycznie rejestruje przestrzenie nazw w węźle głównym. Dowolne przestrzenie nazw, które nie znajdują się w głównym węźle, musisz się zarejestrować. Powinno to zadziałać:

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

Alternatywnie możesz całkowicie usunąć przestrzenie nazw. Wykonuj to tylko, jeśli masz pewność, że nie będzie żadnych konfliktów nazw węzłów.

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

Awesome działało idealnie, dzięki! – Jamie

+3

+1 Yeah remove_namespaces FTW! –

+1

Dziękujemy! to jest magia! – Jirapong

1

Przy prawidłowo zarejestrowany przedrostek opf dla 'http://www.idpf.org/2007/opf' URI przestrzeni nazw, a dc dla 'URI', trzeba:

/*/opf:metadata/dc:title 

Uwaga: xmlns i xml zarezerwowane są prefiksy, które nie mogą być przypisane do każdej innej przestrzeni nazw URI niż wbudowane 'http://www.w3.org/2000/xmlns/' i 'http://www.w3.org/XML/1998/namespace'.

+0

Nie działało jak doc.xpath ('/ */opf: metadata/dc: title') # => "' assess ": Nieokreślony przedrostek przestrzeni nazw" – Jamie

+0

@Jamie: Czy rzeczywiście przeczytałeś odpowiedź? Pierwsze zdanie zaczyna się * "Z prawidłowo zarejestrowanym przedrostkiem" * ... –

+0

@Alejandro przepraszam Nie do końca rozumiem, czy istnieje sposób, aby to zrobić bez prefiksu dla opf (z wyjątkiem sposobu opisanego w odpowiedzi @ mark-thomas), to byłoby miło zrobić to w jednym zapytaniu xpath. – Jamie

0

Jako alternatywę jawnie konstruowania skrót URI przestrzeni nazw, można pobrać definicje przestrzeni nazw z elementu xml, gdzie są one zdefiniowane.

Korzystanie przykład:

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

Zauważ, że druga XPath mógł już również zostały:

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

Ale dlaczego szukaj od korzenia, gdy masz bliżej przodka? Powinieneś także rozważyć element definiujący przestrzeń nazw wraz z jego dziećmi jako "zasięg" przestrzeni nazw. Wyszukiwanie ograniczonego zakresu jest mniej kłopotliwe i pozwala uniknąć subtelnych błędów.

Powiązane problemy