¿Cómo puedo obtener Nokogiri para analizar y devuelve un documento XML?
-
18-09-2019 - |
Pregunta
He aquí una muestra de algunas rarezas:
#!/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"
Al ejecutar este devuelve:
without read: Nokogiri::XML::Document
with read: Nokogiri::HTML::Document
Sin el XML devuelve read
, y con ella es HTML? La página Web se define como "XHTML de transición", por lo que en un principio pensé Nokogiri debe haber sido la lectura de "Content-Type" de OpenURI de la corriente, pero que devuelve 'text/html'
:
(rdb:1) doc = open(('http://weblog.rubyonrails.org/'))
(rdb:1) doc.content_type
"text/html"
que es lo que el servidor está regresando. Por lo tanto, ahora estoy tratando de averiguar por qué Nokogiri está regresando dos valores diferentes. No parece ser analizar el texto y el uso de la heurística para determinar si el contenido es HTML o XML.
Lo mismo está sucediendo con el canal de información ATOM apuntado por esa página:
(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
Tengo que ser capaz de analizar una página sin saber lo que es por adelantado, ya sea HTML o una alimentación (RSS o ATOM) y fiable determinar qué es. Pregunté Nokogiri para analizar el cuerpo ya sea de un archivo HTML o XML feed, pero estoy viendo los resultados inconsistentes.
pensé que podría escribir algunas pruebas para determinar el tipo, pero luego me encontré con XPaths no encontrar elementos, pero las búsquedas regulares de trabajo:
(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 que pensé sería trabajar con XML, pero los resultados no parecen dignos de confianza tampoco.
Estas pruebas se puede hacer todo en mi caja de Ubuntu, pero he visto el mismo comportamiento en mi Macbook Pro. Me gustaría saber que estoy haciendo algo mal, pero no he visto un ejemplo para el análisis y la búsqueda de que me dio resultados consistentes. ¿Alguien puede mostrar el error de mis maneras?
Solución
Tiene que ver con la forma de analizar método funciona. Aquí está la fuente:
# 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 clave es la if string =~ /^\s*<[^Hh>]*html/i # Probably html
línea. Cuando sólo tiene que utilizar open
, devuelve un objeto que no funciona con expresiones regulares, por lo que siempre devuelve falso. Por otro lado, read
devuelve una cadena, por lo que podría ser considerado como HTML. En este caso se trata, ya que coincide con la expresión regular. Aquí está el comienzo de esa cadena:
<!DOCTYPE html PUBLIC
La expresión coincide con el "! DOCTYPE" a [^Hh>]*
y luego coincide con el "html", asumiendo así que es HTML. ¿Por qué una persona seleccionada esta expresión regular para determinar si el archivo es HTML está más allá de mí. Con esta expresión regular, un archivo que comienza con una etiqueta como <definitely-not-html>
se considera HTML, pero se considera <this-is-still-not-html>
XML. Usted es probablemente el mejor de permanecer lejos de esta función muda e invocando Nokogiri::HTML::Document#parse
o Nokogiri::XML::Document#parse
directamente.
Otros consejos
En respuesta a esta parte de su pregunta:
pensé que podría escribir algunas pruebas a determinar el tipo, pero luego me encontré con XPaths no encontrar elementos, pero búsquedas regulares de trabajo:
acabo de venir a través de este problema utilizando nokogiri a analizar un átomo de alimentación. El problema parecía a la declaración de espacio de nombres en el anonimato:
<feed xmlns="http://www.w3.org/2005/Atom">
La eliminación de la declaración xmlns desde el XML de origen permitiría Nokogiri a buscar con XPath como de costumbre. Extracción de que la declaración de la alimentación, obviamente, no era una opción aquí, así que en vez me acaba de quitar los espacios de nombre del documento después del análisis. por ejemplo:
doc = Nokogiri.parse(open('http://feeds.feedburner.com/RidingRails'))
doc.remove_namespaces!
doc.xpath('/feed/entry').length
feo lo sé, pero lo hizo el truco.