如何使用 Ruby 和 Nokogiri 解析 LI/DL/DD 标签结构



我正在尝试解析包含有序列表和DL/DD标签的html。目标是创建一个 xml 结构,逐项列出添加某些属性的每个标记的内容。 最终使结构展平(所需的输出将显示在问题末尾)。

下面是存储在文件(包含在测试中.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>

HTML 的输出(显示此处,您看不到在浏览器中看到的缩进):

  1. 项目 1 - 级别 1
    项目 1.1 - 级别 2
    项目 1.2 - 级别 2
  2. 项目 2 - 级别 1
    项目 2.1 - 级别 2
    项目 2.1.1 - 级别 3
    项目 2.1.2 - 级别 3
    项目 2.1.2.1 - 级别 4
    项目 2.1.2.2 - 级别 4
    项目 2.2 - 级别 2
    项目 2.2.1 - 级别 3
    项目 2.2.2 - 级别 3
    项目 2.2.2.1 - 级别 4
    项目 2.2.2.2 - 级别 4
    项目 2.2.3 - 级别 3
    项目 2.2.3.1 - 级别 4
    项目 2.2.3.2 - 级别 4
    项目 2.2.4 - 级别 3
  3. 项目 3 - 级别 1
    项目 3.1 - 级别 2
    项目 3.2 - 级别 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>

请注意,我们希望通过遍历结构来派生层次结构,而不是从每个 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  
您可以使用

node_name 方法来确定什么是文本,什么是子文本,下面是一个示例函数,它吐出 ol 下的 html 标记的名称:

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]")

(我上面跳过的文本节点是标签的文本内容)

相关内容

  • 没有找到相关文章

最新更新