2011-05-18 59 views
1

我想解析包含有序列表以及DL/DD標籤的html。目標是創建一個xml結構,將每個標記的內容逐項添加一些屬性。在最後效果平坦的結構(期望的輸出將顯示在問題的最後)。如何使用Ruby和Nokogiri解析LI/DL/DD標籤結構?

這裏是存儲在一個文件的HTML的例子(包含在test.html中在我的代碼):從HTML(

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Test Structure</title> 
</head> 
<body> 
<ol><li>Item 1 - Level 1 
<dl><dd>Item 1.1 - Level 2 
</dd><dd>Item 1.2 - Level 2 
</dd></dl> 
</li><li>Item 2 - Level 1 
<dl><dd>Item 2.1 - Level 2 
<dl><dd>Item 2.1.1 - Level 3 
</dd><dd>Item 2.1.2 - Level 3 
<dl><dd>Item 2.1.2.1 - Level 4 
</dd><dd>Item 2.1.2.2 - Level 4 
</dd></dl> 
</dd></dl> 
</dd><dd>Item 2.2 - Level 2 
<dl><dd>Item 2.2.1 - Level 3 
</dd><dd>Item 2.2.2 - Level 3 
<dl><dd>Item 2.2.2.1 - Level 4 
</dd><dd>Item 2.2.2.2 - Level 4 
</dd></dl> 
</dd><dd>Item 2.2.3 - Level 3 
<dl><dd>Item 2.2.3.1 - Level 4 
</dd><dd>Item 2.2.3.2 - Level 4 
</dd></dl> 
</dd><dd>Item 2.2.4 - Level 3 
</dd></dl> 
</dd></dl> 
</li><li>Item 3 - Level 1 
<dl><dd>Item 3.1 - Level 2 
</dd><dd>Item 3.2 - Level 2 
</dd></dl> 
</li></ol> 
</body> 
</html> 

輸出這裏顯示你沒有看到,你會在看到壓痕瀏覽器):

 

         
 
  1. Item 1 - Level 1
    Item 1.1 - Level 2
    Item 1.2 - Level 2
  2. Item 2 - Level 1
    Item 2.1 - Level 2
    Item 2.1.1 - Level 3
    Item 2.1.2 - Level 3
    Item 2.1.2.1 - Level 4
    Item 2.1.2.2 - Level 4
    Item 2.2 - Level 2
    Item 2.2.1 - Level 3
    Item 2.2.2 - Level 3
    Item 2.2.2.1 - Level 4
    Item 2.2.2.2 - Level 4
    Item 2.2.3 - Level 3
    Item 2.2.3.1 - Level 4
    Item 2.2.3.2 - Level 4
    Item 2.2.4 - Level 3
  3. Item 3 - Level 1
    Item 3.1 - Level 2
    Item 3.2 - Level 2

所需的輸出:

<job> 
<req level='1'>Item 1 - Level 1</req> 
<req level='1.1'>Item 1.1 - Level 2</req> 
<req level='1.2'>Item 1.2 - Level 2</req> 
<req level='2'>Item 2 - Level 1</req> 
<req level='2.1'>Item 2.1 - Level 2</req> 
<req level='2.1.1'>Item 2.1.1 - Level 3</req> 
<req level='2.1.2'>Item 2.1.2 - Level 3</req> 
<req level='2.1.2.1'>Item 2.1.2.1 - Level 4</req> 
<req level='2.1.2.2'>Item 2.1.2.2 - Level 4</req> 
<req level='2.2'>Item 2.2 - Level 2</req> 
<req level='2.2.1'>Item 2.2.1 - Level 3</req> 
<req level='2.2.2'>Item 2.2.2 - Level 3</req> 
<req level='2.2.2.1'>Item 2.2.2.1 - Level 4</req> 
<req level='2.2.2.2'>Item 2.2.2.2 - Level 4</req> 
<req level='2.2.3'>Item 2.2.3 - Level 3</req> 
<req level='2.2.3.1'>Item 2.2.3.1 - Level 4</req> 
<req level='2.2.3.2'>Item 2.2.3.2 - Level 4</req> 
<req level='2.2.4'>Item 2.2.4 - Level 3</req> 
<req level='3'>Item 3 - Level 1</req> 
<req level='3.1'>Item 3.1 - Level 2</req> 
<req level='3.2'>Item 3.2 - Level 2</req> 
</job> 

請注意,我們要來回派生層次結構m遍歷結構,而不是從每個LI和DD屬性的實際內容中進行遍歷......我的示例的內容列出了層次結構(1,1.1,1.2 ...),但在實際數據中我們不會看到這些內容。 「level」屬性應該反映結構的遍歷。

我對Ruby和Nokogiri都很陌生,但這裏是我嘗試閱讀HTML(還沒有創建XML)。我堅持分離出LI節點和內容。我已經使用.eachchildren.each試過,等:

require 'rubygems' 
require 'open-uri' 
require 'nokogiri' 

url = "test.html" 
doc = Nokogiri::HTML(open(url)) 
line = "1" 
doc.css("ol[1]").children.each do |n| 
    puts line + n.content.to_s 
    line.succ! 
    n.children do |c| 
     puts line + c.content.to_s 
     line.succ! 
    end 
end 

回答

1

可以使用node_name方法來確定什麼是文字的,什麼是一個孩子,這裏說下吐出來的是HTML標籤名稱的樣本函數OL:

def traverse(node, indent = 0) 
    node.children.each do |child| 
    next if child.node_name == "text" 
    puts " "*indent + child.node_name 
    traverse(child, indent+1) 
    end 
end 

traverse doc.css("ol[1]") 

(我是上面跳過文本節點是標籤的文本內容)

+0

哇,這是快的CAM ... THX!這給我提供了node_name列表,並且實際上正確地反映了層次結構。當我從'child.node_name'更改爲'child.text'時,它並不總是給我一個單一的值。 – BCinAustin 2011-05-18 20:03:57

+0

@BCinAustin:'text'方法遞歸地抓取所有孩子的'text'。你只需要在具有node_name'text'的子節點上調用'text'。 (所以,不要用'next'跳過文本節點,在那時打印出來) – cam 2011-05-18 21:17:54

+0

完美!這正是我所錯過的。再次感謝Cam! – BCinAustin 2011-05-18 21:34:38