Frage

Hier ist ein Beispiel von einiger Merkwürdigkeit:

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

Ausführen dieses zurückgibt:

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

Ohne die read kehrt XML, und damit ist HTML? Die Webseite wird als „XHTML Übergang“ definiert, so dachte zuerst, ich Nokogiri Lesen „Content-Type“ der openURI gewesen sein muß aus dem Strom, aber das gibt 'text/html':

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

das ist, was der Server zurückkehrt. So, jetzt versuche ich herauszufinden, warum Nokogiri wird zwei verschiedene Werte zurück. Es scheint nicht, den Text zu parsen und unter Verwendung von Heuristiken, um zu bestimmen, ob der Inhalt HTML oder XML.

Das gleiche wird mit dem ATOM-Feed geschieht, auf das dieser Seite:

(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

Ich muss in der Lage, eine Seite zu analysieren, ohne zu wissen, was es im Voraus ist, entweder HTML oder einen Feed (RSS oder ATOM) und zuverlässig bestimmen, welche es ist. Ich fragte Nokogiri den Körper entweder eine HTML oder XML-Feed-Datei zu analysieren, aber ich diese inkonsistenten Ergebnisse zu sehen.

Ich dachte, ich einige Tests schreiben konnte, den Typ zu bestimmen, aber dann lief ich in XPaths nicht Elemente zu finden, aber regelmäßige sucht Arbeit:

(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

Ich dachte XPaths würde mit XML arbeiten, aber die Ergebnisse entweder nicht vertrauenswürdig aussehen.

fertig waren diese Tests alle auf meiner Ubuntu-Box, aber ich habe das gleiche Verhalten auf meinem MacBook Pro zu sehen. Ich würde gerne ich etwas falsch mache, um herauszufinden, aber ich habe nicht ein Beispiel für die Analyse und die Suche gesehen, das mir konsistente Ergebnisse gab. Kann mir jemand den Fehler meiner Wege zeigen?

War es hilfreich?

Lösung

Es hat mit der Art und Weise Nokogiri zu analysieren funktioniert. Hier ist die Quelle:

# 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

Der Schlüssel ist die Linie if string =~ /^\s*<[^Hh>]*html/i # Probably html. Wenn Sie nur open verwenden, gibt es ein Objekt, das nicht mit Regex funktioniert, also immer wird false zurückgegeben. Auf der anderen Seite, gibt read einen String, so dass es könnte als HTML betrachtet werden. In diesem Fall ist es, weil es, dass der Regex übereinstimmt. Hier ist der Anfang dieser Zeichenfolge:

<!DOCTYPE html PUBLIC

Die Regex entspricht den „! DOCTYPE“ [^Hh>]* und dann stimmt mit dem „html“, so HTML es ist anzunehmen. Warum jemand diese regex ausgewählt, um zu bestimmen, ob die Datei HTML ist mir schleierhaft. Mit dieser regex einer Datei, die mit einem Tag wie <definitely-not-html> beginnt, wird HTML betrachtet, aber <this-is-still-not-html> wird XML betrachtet. Sie sind wahrscheinlich am besten aus dieser stummen Funktion bleibt weg und Aufrufe Nokogiri::HTML::Document#parse oder Nokogiri::XML::Document#parse direkt.

Andere Tipps

zu diesem Teil Ihrer Frage Antwort:

  

Ich dachte, ich könnte einige Tests schreiben   die Art bestimmen, aber dann lief ich in   XPaths nicht finden, Elemente, aber   regelmäßige Suche arbeiten:

Ich habe gerade über dieses Problem kommt nokogiri mit einem Atom-Feed zu analysieren. Das Problem schien bis auf die anonyme Namensraum-Deklaration:

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

Das Entfernen der xmlns-Deklaration aus der Quelle xml würde Nokogiri ermöglichen, mit XPath wie gewohnt zu suchen. Das Entfernen dieser Erklärung aus dem Futter war offensichtlich keine Option hier, also ich stattdessen entfernt nur die Namensräume aus dem Dokument nach dem Parsen. zB:

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

Hässliche ich weiß, aber es hat den Trick.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top