the*_*Man 5 ruby xpath nokogiri xml-parsing
这是一些奇怪的样本:
#!/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"
Run Code Online (Sandbox Code Playgroud)
运行此返回:
without read: Nokogiri::XML::Document
with read: Nokogiri::HTML::Document
Run Code Online (Sandbox Code Playgroud)
没有read返回XML,并且它是HTML?网页被定义为"XHTML过渡",所以起初我认为Nokogiri必须从流中读取OpenURI的"内容类型",但是返回'text/html':
(rdb:1) doc = open(('http://weblog.rubyonrails.org/'))
(rdb:1) doc.content_type
"text/html"
Run Code Online (Sandbox Code Playgroud)
这是服务器返回的内容.所以,现在我想弄清楚为什么Nokogiri会返回两个不同的值.它似乎没有解析文本并使用启发式方法来确定内容是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
Run Code Online (Sandbox Code Playgroud)
我需要能够在不知道它是什么的情况下解析页面,HTML或者提要(RSS或ATOM)并可靠地确定它是什么.我让Nokogiri解析HTML或XML feed文件的正文,但我看到了那些不一致的结果.
我以为我可以编写一些测试来确定类型,但后来我遇到xpaths没有找到元素,但常规搜索工作:
(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
Run Code Online (Sandbox Code Playgroud)
我认为xpaths可以使用XML,但结果看起来也不值得信赖.
这些测试都是在我的Ubuntu盒子上完成的,但我在Macbook Pro上看到过相同的行为.我很想知道我做错了什么,但我没有看到解析和搜索的例子,这给了我一致的结果.谁能告诉我我的方式错误?
Pes*_*sto 13
它与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
Run Code Online (Sandbox Code Playgroud)
关键是线if string =~ /^\s*<[^Hh>]*html/i # Probably html.当你刚才使用时open,它会返回一个不能与正则表达式一起使用的对象,因此它总是返回false.另一方面,read返回一个字符串,因此可以将其视为HTML.在这种情况下,它是,因为它匹配该正则表达式.这是该字符串的开头:
<!DOCTYPE html PUBLIC
Run Code Online (Sandbox Code Playgroud)
正则表达式匹配"!DOCTYPE" [^Hh>]*然后匹配"html",因此假设它是HTML.为什么有人选择这个正则表达式来确定文件是否是HTML是超出我的.使用此正则表达式,以标记开头的文件<definitely-not-html>被视为HTML,但<this-is-still-not-html>被视为XML.你可能最好关闭此功能哑掉停留并调用Nokogiri::HTML::Document#parse或Nokogiri::XML::Document#parse直接.
小智 5
回答你的这部分问题:
我以为我可以编写一些测试来确定类型,但后来我遇到xpaths没有找到元素,但常规搜索工作:
我刚刚使用nokogiri来解析原子进给问题.问题似乎取决于匿名名称空间声明:
<feed xmlns="http://www.w3.org/2005/Atom">
Run Code Online (Sandbox Code Playgroud)
从源xml中删除xmlns声明将使Nokogiri能够像往常一样使用xpath进行搜索.从feed中删除该声明显然不是一个选项,所以我只是在解析后从文档中删除了名称空间.例如:
doc = Nokogiri.parse(open('http://feeds.feedburner.com/RidingRails'))
doc.remove_namespaces!
doc.xpath('/feed/entry').length
Run Code Online (Sandbox Code Playgroud)
丑陋我知道,但它做到了.