2014-07-25 71 views
2

解析請看下面的HTML:使用XPath

<div class='data'> 
    <div class='user_name'>Lankesh</div> 
    <div class='user_details'> 
    <div class='country'>Srilanka</div> 
    <div class='age'>9</div> 
    </div> 
    <div class='user_name'>Bob</div> 
    <div class='user_details'> 
    <div class='country'>US</div> 
    <div class='age'>54</div> 
    </div> 
    <div class='user_name'>Deiter</div> 
    <div class='user_details'> 
    <div class='country'>Germany</div> 
    <div class='age'>34</div> 
    </div> 
    <div class='user_name'>Yakob</div> 
    <div class='user_details'> 
    <div class='country'>Syria</div> 
    <div class='age'>90</div> 
    </div> 
    <div class='user_name'>Qureshi</div> 
    <div class='user_details'> 
    <div class='country'>Afgan</div> 
    <div class='age'>56</div> 
    </div> 
    <div class='user_name'>Smith George</div> 
    <div class='user_details'> 
    <div class='country'>India</div> 
    <div class='age'>23</div> 
    </div> 
</div> 

而下面的Ruby代碼:

require 'nokogiri' 

sample_html = File.open("r.htm", "r").read 

n = Nokogiri::HTML::parse sample_html 

xpaths = {} 

xpaths[:name] = "//div[@class = 'user_name']/text()" 
xpaths[:country] = "//div[@class = 'country']/text()" 
xpaths[:age] = "//div[@class = 'age']/text()" 

full_path = xpaths.values.join(" | ") 

n.xpath(full_path).each do |i| 
    puts i 
end 

這工作來提取數據,可是我怎麼能塊(姓名,年齡和國家)等等我可以更容易地將解析的數據提取到結構中。

  • 由於name位於user_details塊之外,因此我無法編寫如下查詢://div[@class = 'user_details']並提取每個屬性。
  • 我知道我可以將數組分成3組;但我正在尋找基於xpath的解決方案,因爲我的實際需求具有不同數量的子屬性。
  • 愚蠢,但:無論如何以某種方式注入字符提取文本,在解析?

任何想法?

回答

0

讓我說這將是更好地調整HTML來包裝每個用戶擋在了自己的包含分區開始了:

<div class='user'> 
    <div class='name'>John</div> 
    <div class='details'> 
     <div class='country'>US</div> 
     ... 
    </div> 
</div> 

然後,你可以簡單地查詢分別使用"//div[@class = 'user']"每個用戶塊。不過,你可能不能控制HTML。

鑑於目前的情況,我會建議簡單地獲得user_name div以及user_details div並將它們壓縮在一起。然後,您可以根據基於子div(.xpath("div"))的用戶詳細信息創建一個Hash,這將適用於任何數量的user_details,並將其class屬性用作散列鍵,並將其文本用作值。請注意,此實現僅適用於單級user_details。當然,如果不是所有的user_details子div都有一個class屬性,這個必須調整。但從他們的示例輸入來看,他們確實如此。

require 'pp' 
require 'nokogiri' 

sample_html = File.open("r.htm", "r").read 

n = Nokogiri::HTML::parse sample_html 

user_names = n.xpath("//div[@class = 'user_name']") 
user_details = n.xpath("//div[@class = 'user_details']") 

users = user_names.zip(user_details).map do |name, details| 
    { 
    name: name.text, 
    details: Hash[details.xpath("div").map { |d| [d['class'].to_sym, d.text] }] 
    } 
end 

pp users 

# [{:name=>"Lankesh", :details=>{:country=>"Srilanka", :age=>"9"}}, 
# {:name=>"Bob", :details=>{:country=>"US", :age=>"54"}}, 
# {:name=>"Deiter", :details=>{:country=>"Germany", :age=>"34"}}, 
# {:name=>"Yakob", :details=>{:country=>"Syria", :age=>"90"}}, 
# {:name=>"Qureshi", :details=>{:country=>"Afgan", :age=>"56"}}, 
# {:name=>"Smith George", :details=>{:country=>"India", :age=>"23"}}] 
+0

是的,你有正確的猜測,我沒有控制HTML。我理解拉鍊。但沒有辦法使用XPath完成此操作(也許我正在對XPath進行映像) –

+0

我不這麼認爲,主要是因爲XPath返回了一個平坦的結果列表,並且因爲您的來源未分組也不會結果。您是否有任何理由只希望它在XPath中完成?你說這是因爲user_details有不同數量的屬性,但我的解決方案解決它的問題時,解析爲數據結構,這正是你想要的:)? –

+0

你是對的,但不知何故,它被實際解析的困惑所困惑,那就是爲什麼我要進一步尋找。你回答肯定是對的。但是,只是尋找我發佈的另一個問題;多數民衆贊成我真的想要幫助,試圖瞭解XPath在這。 –