2011-01-14 36 views
32

Tôi đang cố gắng lấy phần tử dc:title bằng xpath. Tôi có thể lấy siêu dữ liệu bằng cách sử dụng mã sau đây.Truy vấn không gian tên Nokogiri/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> 

Như bạn có thể thấy ở trên dường như hoạt động chính xác. Tuy nhiên tôi dường như không thể lấy thông tin tiêu đề từ cây nút này, tất cả những điều dưới đây đều thất bại.

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 

Ai đó có thể giải thích cách sử dụng không gian tên trong đường dẫn với tài liệu xml ở trên.

Trả lời

60

Tất cả các không gian tên cần phải được đăng ký khi phân tích cú pháp. Nokogiri tự động đăng ký không gian tên trên nút gốc. Bất kỳ không gian tên nào không nằm trong nút gốc bạn phải tự đăng ký. Điều này sẽ hoạt động:

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

Cách khác, bạn có thể xóa hoàn toàn không gian tên. Chỉ làm điều này nếu bạn chắc chắn sẽ không có tên nút xung đột.

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

Làm việc tuyệt vời một cách hoàn hảo, cảm ơn! – Jamie

+3

+1 Yeah remove_namespaces FTW! –

+1

Cảm ơn bạn !!! đây là phép thuật! – Jirapong

1

Với đăng ký đúng prefix opf cho 'http://www.idpf.org/2007/opf' namespace URI, và dc cho 'URI', bạn cần:

/*/opf:metadata/dc:title 

Note: xmlnsxml được dành tiền tố mà không thể bị ràng buộc với bất kỳ không gian tên khác URI so với được xây dựng trong 'http://www.w3.org/2000/xmlns/''http://www.w3.org/XML/1998/namespace'.

+0

Dường như không hoạt động doc.xpath ('/ */opf: siêu dữ liệu/dc: title') # => "' assessment ': Tiền tố không gian tên không xác định " – Jamie

+0

@Jamie: Bạn có thực sự đọc câu trả lời không? Câu đầu tiên bắt đầu * "Với tiền tố đăng ký đúng" * ... –

+0

@Alejandro xin lỗi tôi không hoàn toàn hiểu là có cách để làm điều đó mà không có tiền tố cho opf (ngoại trừ cách được mô tả trong câu trả lời @ mark-thomas), nó 'd được tốt đẹp để làm điều đó trong một truy vấn xpath. – Jamie

0

Để thay thế một cách rõ ràng xây dựng băm của URI không gian tên, bạn có thể truy xuất định nghĩa vùng tên từ phần tử xml nơi chúng được xác định.

Sử dụng ví dụ của bạn:

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

Lưu ý rằng xpath thứ hai có thể cũng đã được:

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

Nhưng tại sao tìm kiếm từ gốc khi bạn có một tổ tiên gần? Ngoài ra, bạn nên xem xét phần tử xác định không gian tên cộng với phần tử con của nó như là "phạm vi" của vùng tên. Tìm kiếm phạm vi giới hạn ít gây nhầm lẫn và tránh các lỗi tinh vi.

Các vấn đề liên quan