كيف يمكنني الحصول على Nokogiri لتحليل وإرجاع مستند XML؟

StackOverflow https://stackoverflow.com/questions/1157138

سؤال

إليك عينة من بعض الغرابة:

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

بدون ال read إرجاع XML، ومعها HTML؟ يتم تعريف صفحة الويب على أنها "XHTML الانتقالية"، لذلك في البداية اعتقدت أن Nokogiri يجب أن يقرأ "نوع المحتوى" OpenUri من الدفق، ولكن هذا يعود 'text/html':

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

وهو ما يعود الخادم. لذلك، الآن أحاول معرفة سبب إرجاع Nokogiri قيمتين مختلفتين. لا يبدو أنه يقوم بتحليل النص واستخدام الاسلكية لتحديد ما إذا كان المحتوى هو HTML أو XML.

يحدث نفس الشيء مع موجز الذرة المدببة لهذه الصفحة:

(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) وتحديد موثوق ذلك. طلبت من nokogiri لتحليل الجسم إما ملف تغذية HTML أو XML، لكنني أرى تلك النتائج غير المتسقة.

اعتقدت أنني أستطيع أن أكتب بعض الاختبارات لتحديد النوع ولكن ثم ركضت إلى 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. أحب أن أعرف أنني أفعل شيئا خاطئا، لكنني لم أر مثالا على تحليل والبحث الذي أعطاني نتائج متسقة. هل يمكن لأي شخص أن يظهر لي خطأ طرقي؟

هل كانت مفيدة؟

المحلول

يجب أن تفعل مع طريقة Nokogiri طريقة تحليل يعمل. إليك المصدر:

# 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, ، تقوم بإرجاع كائن لا يعمل مع Regex، وبالتالي فإنه يرجع دائما خطأ. من ناحية أخرى، read إرجاع سلسلة، لذلك استطاع تعتبر HTML. في هذه الحالة، لأنه يطابق هذا Regex. ها هي بداية تلك السلسلة:

<!DOCTYPE html PUBLIC

يطابق Regex من "! doctype" [^Hh>]* ثم يطابق "HTML"، وبالتالي افتراض أنه HTML. لماذا اختار شخص ما هذا Regex لتحديد ما إذا كان الملف هو HTML يتجاوزني. مع هذا Regex، ملف يبدأ علامة مثل <definitely-not-html> يعتبر HTML، ولكن <this-is-still-not-html> يعتبر XML. ربما تكون أفضل من البقاء بعيدا عن هذه الوظيفة البكمية والإحتسار Nokogiri::HTML::Document#parse أو Nokogiri::XML::Document#parse مباشرة.

نصائح أخرى

الاستجابة لهذا الجزء من سؤالك:

اعتقدت أنني أستطيع أن أكتب بعض الاختبارات لتحديد النوع ولكن ثم ركضت إلى xpath لا يجد عناصر، ولكن عمليات البحث العادية تعمل:

لقد صادفت هذه المشكلة باستخدام Nokogiri لتحليل علف الذرة. بدا المشكلة إلى إعلان المساحة المجهولية:

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

إزالة إعلان XMLNS من مصدر XML سيمكن Nokogiri للبحث مع XPath حسب المعتاد. من الواضح أن إزالة هذا التصريح من الأعلاف لم يكن خيارا هنا، لذلك بدلا من ذلك، أزلت فقط أسماء الأسماء من المستند بعد التحليل. على سبيل المثال:

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

قبيح أعرف، لكنه فعلت الخدعة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top