2009-07-21 32 views
5

Burada bir tuhaflık örneği var:Bir XML belgesini ayrıştırmak ve döndürmek için Nokogiri'yi nasıl alabilirim?

#!/usr/bin/ruby 

require 'rubygems' 
require 'open-uri' 
require 'nokogiri' 

print "without read: ", Nokogiri(open('http://weblog.rubyonrails.org/')).class, "\n" 
print "with read: ", Nokogiri(open('http://weblog.rubyonrails.org/').read).class, "\n" 

Bu döndürmeyi döndürür:

without read: Nokogiri::XML::Document 
with read: Nokogiri::HTML::Document 

read olmadan XML döndürür ve HTML ile mi? Web sayfası "XHTML geçişi" olarak tanımlanmıştır, bu yüzden ilk önce Nokogiri'nin OpenURI'nin "içerik türü" ni akıştan okuması gerektiğini düşünmüştüm, ancak 'text/html':

(rdb:1) doc = open(('http://weblog.rubyonrails.org/')) 
(rdb:1) doc.content_type 
"text/html" 

değerini döndürüyor. . Şimdi, Nokogiri'nin neden iki farklı değer döndürdüğünü anlamaya çalışıyorum. Metnin ayrıştırılması ve içeriğin HTML mi yoksa XML mi olduğunu belirlemek için buluşsal yöntemler kullanmıyor gibi görünmektedir.

Aynı şey bu sayfa tarafından işaret edilen ATOM besleme ile gerçekleşiyor:

(rdb:1) doc = Nokogiri.parse(open('http://feeds.feedburner.com/RidingRails')) 
(rdb:1) doc.class 
Nokogiri::XML::Document 

(rdb:1) doc = Nokogiri.parse(open('http://feeds.feedburner.com/RidingRails').read) 
(rdb:1) doc.class 
Nokogiri::HTML::Document 

Önceden ne olduğunu bilmeden bir sayfayı ayrıştırabilmem gerekir. veya ATOM) ve güvenilir olduğunu belirler. Nokogiri'den bir HTML veya XML besleme dosyasının gövdesini ayrıştırmasını istedim, ancak bu tutarsız sonuçları görüyorum.

Ben türünü belirlemek için bazı testler yazabileceğimi düşündüm ama sonra elementleri bulamayan xpaths'e rastladım ama normal aramalar:

(rdb:1) doc = Nokogiri.parse(open('http://feeds.feedburner.com/RidingRails')) 
(rdb:1) doc.class 
Nokogiri::XML::Document 
(rdb:1) doc.xpath('/feed/entry').length 
0 
(rdb:1) doc.search('feed entry').length 
15 

Ben xpaths XML ile çalışacağını düşündüm ama sonuçlar ya güvenilir görünmek.

Bu testlerin hepsi Ubuntu kutumda yapıldı, ancak Macbook Pro'mda da aynı davranışı gördüm. Yanlış bir şey yaptığımı öğrenmeyi çok isterdim, ancak bana tutarlı sonuçlar veren ayrıştırma ve arama için bir örnek görmedim. Kimse bana yollarımın hatasını gösterebilir mi?

+0

İronik bu aslında bir soru ... –

cevap

12

Bu, Nokogiri'nin parse method çalışmalarıyla ilgilidir. İşte kaynağıdır:

# File lib/nokogiri.rb, line 55 
    def parse string, url = nil, encoding = nil, options = nil 
     doc = 
     if string =~ /^\s*<[^Hh>]*html/i # Probably html 
      Nokogiri::HTML::Document.parse(string, url, encoding, options || XML::ParseOptions::DEFAULT_HTML) 
     else 
      Nokogiri::XML::Document.parse(string, url, encoding, options || XML::ParseOptions::DEFAULT_XML) 
     end 
     yield doc if block_given? 
     doc 
    end 

anahtar hattı if string =~ /^\s*<[^Hh>]*html/i # Probably html olduğunu. Sadece open kullandığınızda, regex ile çalışmayan bir nesne döndürür, bu nedenle her zaman false döndürür. Öte yandan, read bir dize döndürür, bu nedenle HTML olarak kabul edilebilir. Bu durumda, çünkü bu regex ile eşleşir. İşte İpin başlangıçtır:

<!DOCTYPE html PUBLIC 

regex böylece HTML olduğunu varsayarak, [^Hh>]* için "! DOCTYPE" ile eşleşir ve ardından "html" ile eşleşir. Birisi dosyanın HTML olup olmadığını belirlemek için bu regex'i neden seçti? Bu regex ile <definitely-not-html> gibi bir etiketle başlayan bir dosya HTML olarak kabul edilir, ancak <this-is-still-not-html> XML olarak kabul edilir. Muhtemelen bu aptal işlevden uzak kalmak ve doğrudan Nokogiri::HTML::Document#parse veya Nokogiri::XML::Document#parse'u çağırmaktan uzaksınız.

+0

Ah DEĞİLDİR. Ve Ugh. Evet, çok kolay aldatılmış. Etrafında çalışmak için "/ html/head" için bazı sınamalar yapan bazı belge türleri ve RSS ve ATOM etiketleri için bazı yöntemler yazdım ve HTML, RSS ve ATOM belgelerini güvenilir şekilde yakalamış görünüyorlar. Bir belgeyi hem HTML :: Document hem de XML :: Document olarak ayrıştırıyorum ve bunu yapmaktan hoşlanmıyorum. Sanırım Hpricot bir puan atar, çünkü sadece bir belge türü vardır. Şimdi, neden bir ".xpath ('/ feed/entry') arama başarısız olur, ancak" .search (feed entry) "bir nokogiri :: XML :: Document üzerinde başarılı olur? t tutarlı görünmektedir. –

+3

Teknik CSS seçici 'besleme entry'/yem/entry'' XPath eşdeğer değildir. eşdeğer XPath // yem // entry' 'dır. Atom durumunda, orijinal XPath'dir Yine de sorun şu ki, ad alanlarını da eklemelisin. Bunu dene: '/ xmlns: feed/xmlns: entry' – Pesto

+0

Teşekkürler Pesto, çok yardımcı oldun! –

5
Sorunuzun bu bölümünde tepki

: Çalışma Ben türünü belirlemek için bazı testler yazabilirsiniz düşündüm ama sonra unsurları görmediklerine XPath'lerdeki koştu

ancak düzenli aramalar:

Ben sadece bir atom feed ayrıştırmak Nokogiri kullanarak bu sorunla karşılaştık. Sorun anonim ad-uzay ilanına aşağı gibiydi:

<feed xmlns="http://www.w3.org/2005/Atom"> 

her zamanki gibi XPath ile arama Nokogiri sağlayacak kaynak xml den xmlns beyanı çıkarılması. feed'den o bildiriyi Çıkarma açıkçası burada bir seçenek değildi, bunun yerine sadece ayrıştırma sonra belgeden ad alanlarını kaldırıldı. örneğin:

doc = Nokogiri.parse(open('http://feeds.feedburner.com/RidingRails')) 
doc.remove_namespaces! 
doc.xpath('/feed/entry').length 

Çirkin biliyorum, ama hile yaptı.

+3

+1 remove_namespaces! yöntemi Bunu hiç bilmedim ve senin yorumun bana inanılmaz miktarda zaman kazandırdı – rhh

+0

Nokogiri sitesi, bunu bilmeniz gereken uyarıyla birlikte bunu yapıyor. çarpışmalar betw een etiketleri, ya da çarpışma varsa, umursamıyorsunuz. –

İlgili konular