5

ここにいくつかの奇妙さのサンプルがあります:

#!/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"

これを実行すると、次が返されます。

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

戻り値 XMLがなく、readそれがあると HTML ですか? Web ページは「XHTML トランジショナル」として定義されているため、最初は Nokogiri がストリームから OpenURI の「content-type」を読み取っていたに違いないと思っていましたが、次のように返されます'text/html'

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

これはサーバーが返すものです。だから、今、Nokogiri が 2 つの異なる値を返す理由を理解しようとしています。テキストを解析し、ヒューリスティックを使用してコンテンツが HTML か XML かを判断しているようには見えません。

そのページが指す ATOM フィードでも同じことが起こっています。

(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

HTML かフィード (RSS または ATOM) かを事前に知らなくても、ページを解析して、それがどちらであるかを確実に判断できる必要があります。HTML または XML フィード ファイルの本文を解析するよう Nokogiri に依頼しましたが、一貫性のない結果が表示されます。

タイプを判別するテストをいくつか書けると思ったのですが、要素を見つけられない xpath に出くわしましたが、通常の検索は機能しています。

(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

xpaths は XML で動作すると考えましたが、結果も信頼できるものではありません。

これらのテストはすべて私の Ubuntu ボックスで行われましたが、Macbook Pro でも同じ動作が見られました。何か間違ったことをしていることを知りたいのですが、一貫した結果が得られる解析と検索の例を見たことがありません。誰かが私のやり方の誤りを教えてくれますか?

4

2 に答える 2

13

それは Nokogiri のparse メソッドが機能する方法に関係しています。ソースは次のとおりです。

# 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

鍵はラインif string =~ /^\s*<[^Hh>]*html/i # Probably htmlです。を使用するだけopenでは、正規表現では機能しないオブジェクトが返されるため、常に false が返されます。一方、read文字列を返すため、HTML と見なすことができます。この場合は、その正規表現に一致するためです。その文字列の始まりは次のとおりです。

<!DOCTYPE html PUBLIC

正規表現は「!DOCTYPE」[^Hh>]*と一致し、次に「html」と一致するため、HTML であると想定されます。ファイルが HTML であるかどうかを判断するために誰かがこの正規表現を選択した理由は、私には理解できません。この正規表現では、のようなタグで始まるファイル<definitely-not-html>は HTML と見なされますが、<this-is-still-not-html>XML と見なされます。おそらく、この愚かな関数から離れて、Nokogiri::HTML::Document#parseまたはNokogiri::XML::Document#parse直接呼び出すことをお勧めします。

于 2009-07-21T13:26:23.110 に答える
5

あなたの質問のこの部分に答える:

タイプを判別するテストをいくつか書けると思ったのですが、要素を見つけられない xpath に出くわしましたが、通常の検索は機能しています。

Nokogiri を使用して Atom フィードを解析しているときに、この問題に遭遇しました。問題は、匿名の名前空間宣言にあるようです。

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

ソース XML から XMLNS 宣言を削除すると、Nokogiri は通常どおり XPath で検索できるようになります。フィードからその宣言を削除することは明らかにここではオプションではありませんでした。そのため、代わりに、解析後にドキュメントから名前空間を削除しました。

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

醜いことはわかっていますが、うまくいきました。

于 2010-06-10T14:45:31.133 に答える