2009-07-21 6 views
5

Nokogiri가 XML 문서를 구문 분석하고 반환하도록하려면 어떻게해야합니까?

#!/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 transitional"로 정의되었으므로 처음에는 Nokogiri가 스트림에서 OpenURI의 "content-type"을 읽었 음에 틀림 없다고 생각했지만 'text/html'을 반환합니다.

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

이는 서버가 반환하는 것입니다. . 이제 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 

HTML 또는 피드 (RSS)가 무엇인지 모른 채 페이지를 파싱 할 수 있어야합니다 또는 ATOM)을 선택하고 그것이 무엇인지를 신뢰성있게 결정하십시오. Nokogiri에게 HTML 또는 XML 피드 파일의 본문을 구문 분석하도록 요청했지만 이러한 일관성없는 결과가 표시됩니다.

형식을 결정하기 위해 몇 가지 테스트를 작성할 수 있다고 생각했지만 요소를 찾지 못하는 xpaths를 만났지만 정기적으로 검색 할 수 있다고 생각했습니다. xpaths는 XML과 작동하지만 결과는 같지 않은 것으로 나타났습니다. 믿을 만하다.

이 테스트는 모두 내 Ubuntu 상자에서 수행되었지만 Macbook Pro에서 동일한 동작을 보았습니다. 내가 잘못하고있는 것을 알고 싶지만 구문 분석과 검색을 통해 일관된 결과를 얻는 예제를 보지 못했습니다. 누구든지 저에게 제 실수의 오류를 보여줄 수 있습니까?

+0

아이러니하게도 실제로 이것은 질문이 아닙니다 ... –

답변

12

Nokogiri의 parse method 작동 방식과 관련이 있습니다. 소스는 다음과 같습니다.

# 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을 사용하면 정규식에서 작동하지 않는 객체를 반환하므로 항상 false를 반환합니다. 반면에 read은 문자열을 반환하므로 을 HTML로 간주 할 수 있습니다. 이 경우 해당 정규식과 일치하기 때문입니다. 여기에 해당 문자열의 시작이다 :

<!DOCTYPE html PUBLIC 

정규식 따라서는 HTML의 가정 [^Hh>]*로! "의 DOCTYPE을"일치 다음 "HTML"를 일치합니다. 파일이 HTML인지 결정하기 위해이 정규식을 선택한 이유가 무엇입니까? 이 정규식을 사용하면 <definitely-not-html>과 같은 태그로 시작하는 파일은 HTML로 간주되지만 <this-is-still-not-html>은 XML로 간주됩니다. 아마도이 벙어리 함수에서 벗어나 Nokogiri::HTML::Document#parse 또는 Nokogiri::XML::Document#parse을 직접 호출하는 것이 가장 좋습니다.

+0

Ah. 그리고 우. 예, 매우 쉽게 바보입니다. "/ html/head"와 RSS 및 ATOM 용 태그에 대한 몇 가지 테스트를 수행하는 두 가지 문서 유형에 대한 몇 가지 메소드를 작성하여 HTML, RSS 및 ATOM 문서를 안정적으로 catch하는 것으로 보입니다. 나는 HTML :: Document와 XML :: Document로 구문 분석을하고 있는데, 그렇게하지 않아도된다. 나는 Hpricot이 하나의 문서 유형만을 가지고 있기 때문에 점수를 얻는다 고 생각합니다. Nokogiri :: XML :: Document에서 ".xpath ('/ feed/entry') 검색이 실패하지만".search (feed entry) "가 성공하는 이유는 무엇입니까? –

+3

기술적으로 CSS 선택자'feed entry'는 XPath'/ feed/entry'와 같지 않습니다. 해당 XPath는'// feed // entry'입니다 Atom의 경우 원래 XPath는 올바른지, 문제는 네임 스페이스를 포함해야한다는 것입니다. 다음을 시도해보십시오 :'/ xmlns : feed/xmlns : entry' – Pesto

+0

감사합니다 Pesto, 당신은 매우 도움이되었습니다! –

5
질문의이 부분에 대한 대응

: 작업 내가 유형을 결정 몇 가지 테스트를 작성할 수 있다고 생각하지만 내가 요소를 발견하지 XPath를 다 퉜다

하지만 일반 검색 :

난 그냥 원자 피드를 구문 분석 nokogiri를 사용 하여이 문제를 건너 왔어요. 문제는 익명의 네임 스페이스 선언에 아래로 보였다 :

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

을 평소에 따라 XPath를 함께 검색 할 노코 기리을 가능하게 할 소스 XML에서 xmlns 선언을 제거. 피드에서 해당 선언을 제거하는 것은 여기서는 옵션이 아니었기 때문에 구문 분석 후에 문서에서 네임 스페이스를 제거했습니다. 예 :

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

미안하지만 나는 속임수를 사용했습니다.

+3

+1 remove_namespaces! 메서드에 대해. 나는 결코 알지 못했고 귀하의 의견은 저에게 엄청난 시간을 절약 해주었습니다. – rhh

+0

Nokogiri 사이트는 당신이 알고 있어야하는 경고와 함께 그 일을 언급합니다. 충돌 태그가 없거나 충돌이 발생해도 상관하지 않습니다. –