Question

Voici un exemple de quelques bizarreries:

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

L'exécution de cette retourne:

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

Sans retourne read XML, et il est HTML? La page Web est définie comme « XHTML transition », donc au début je pensais Nokogiri doit avoir été lu « type de contenu » de openURI du flux, mais qui retourne 'text/html':

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

qui est ce que le serveur retourne. Alors, maintenant, je suis en train de comprendre pourquoi Nokogiri retourne deux valeurs différentes. Il ne semble pas être l'analyse du texte et en utilisant des heuristiques pour déterminer si le contenu est HTML ou XML.

La même chose se produit avec l'ATOM pointée par cette page:

(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

Je dois être capable d'analyser une page sans savoir ce qu'il est en avance, soit en HTML ou un flux (RSS ou ATOM) et déterminer de manière fiable qu'il est. J'ai demandé Nokogiri d'analyser le corps soit un fichier de flux HTML ou XML, mais je vois les résultats incohérents.

Je pensais que je pourrais écrire des tests pour déterminer le type, mais je suis tombé sur XPath ne pas trouver des éléments, mais des recherches régulières de travail:

(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

je me suis dit XPath travailleraient avec XML, mais les résultats ne semble pas digne de confiance non plus.

Ces tests ont tous été effectués sur ma boîte Ubuntu, mais j'ai vu le même comportement sur mon Macbook Pro. J'aimerais savoir que je fais quelque chose de mal, mais je ne l'ai pas vu un exemple pour l'analyse et la recherche qui m'a donné des résultats cohérents. Quelqu'un peut-il me montrer l'erreur de mes manières?

Était-ce utile?

La solution

Il a à voir avec la façon dont Nokogiri méthode parse fonctionne. Voici la source:

# 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

La clé est la ligne if string =~ /^\s*<[^Hh>]*html/i # Probably html. Lorsque vous utilisez juste open, il retourne un objet qui ne fonctionne pas avec regex, donc il retourne toujours faux. D'autre part, read retourne une chaîne, il pourrait être considéré comme HTML. Dans ce cas, il est, car il correspond à cette expression régulière. Voici le début de cette chaîne:

<!DOCTYPE html PUBLIC

Le regex correspond à la « ! DOCTYPE » à [^Hh>]* et correspond alors le « html », assumant ainsi son HTML. Pourquoi quelqu'un choisi cette regex pour déterminer si le fichier est HTML est au-delà de moi. Avec cette regex, un fichier qui commence par une étiquette comme <definitely-not-html> est considéré comme HTML, mais <this-is-still-not-html> est considéré comme XML. Vous êtes probablement mieux de rester loin de cette fonction stupide et invoquer directement Nokogiri::HTML::Document#parse ou Nokogiri::XML::Document#parse.

Autres conseils

En réponse à cette partie de votre question:

  

Je pensais que je pourrais écrire quelques tests à   déterminer le type mais je suis tombé   XPath ne pas trouver des éléments, mais   des recherches régulières de travail:

Je viens sur ce problème en utilisant nokogiri pour analyser un flux d'atomes. Le problème semblait jusqu'à la déclaration espace de nom anonyme:

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

Retrait de la déclaration xmlns du xml source permettrait Nokogiri de recherche avec XPath comme d'habitude. Retrait de cette déclaration de l'alimentation était évidemment pas une option ici, donc au lieu que je viens enlevé les namespaces du document après l'analyse syntaxique. par exemple:

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

Je sais laid, mais il a fait l'affaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top