位置:首页 > Ruby > Ruby程序创建和解析XML文件的方法详解

Ruby程序创建和解析XML文件的方法详解

时间:2026-08-17  |  作者:实验室老王  |  阅读:0

在Ruby的世界里,处理XML文件是家常便饭。无论是生成配置文件,还是解析接口返回的数据,你总得和它打交道。

今天这篇,我们就来聊聊两个最趁手的工具:BuilderREXML。一个负责造,一个负责拆,配合好了,事半功倍。

使用Builder创建XML

先说怎么造一个XML出来。Builder这个库用起来非常清爽,几行代码就能生成结构清晰的文档。

安装它只需要一条命令:

gem install builder

下面来看一个具体例子。我们想生成一个包含书本信息的XML,代码如下:

require 'builder'  

x = Builder::XmlMarkup.new(:target => $stdout, :indent => 1) 
#":target =>$stdout"参数:指示输出内容将被写向标准输出控制台 
#":indent =>1"参数:XML输出形式将被缩进一个空格字符
x.instruct! :xml, :version =>'1.1', :encoding => 'gb2312' 
x.comment! "书本信息" 

x.library("shelf" => "Recent Acquisitions") { 
  x.section("name" => "ruby"){ 
    x.book("isbn" => "0672310001"){ 
      x.title "Programming Ruby"  
      x.author "Yukihiro " 
      x.description "Programming Ruby - The Pragmatic Programmer's Guide" 
    } 
  } 
} 

这里有两个参数值得注意:

  • :target => $stdout:把结果直接打印到控制台上。
  • :indent => 1:让输出带有1个空格的缩进,方便阅读。

最后p x会把生成的XML对象也打印出来。执行后的输出结果如下:

 
 
 
  
Programming Ruby Yukihiro Programming Ruby - The Pragmatic Programmer's Guide

生成结果干净利落,该有的都有。

Ruby程序中创建和解析XML文件的方法

使用REXML解析XML

造完了XML,接下来就得学会怎么读它。REXML是Ruby自带的XML解析库,纯Ruby实现,用起来相当顺手。

它提供了两种主流的解析方式:

  • DOM-like(树解析):整个文档读进内存,变成一棵树。
  • SAX-like(流解析):边读边处理,适合大文件。

下面我们从一个具体的books.xml文件出发,看看怎么玩。

先准备一份示例数据:

 
  
The Ruby Way Hal Fulton Second edition. The book you are now reading. Ain't recursion grand
The Case for Mars Robert Zubrin Pushing toward a second home for the human race. First Man: The Life of Neil A. Armstrong James R. Hansen Definitive biography of the first man on the moon.

1. Tree Parsing(DOM-like)

树解析是最直观的方式。先把文件读进来,然后像操作一棵树一样获取节点。

需要先require相应的库:

require 'rexml/document' 
include REXML 

input = File.new("books.xml") 
doc = Document.new(input) 

root = doc.root 
puts root.attributes["shelf"]   # Recent Acquisitions 

doc.elements.each("library/section") { |e| puts e.attributes["name"] } 
# Output: 
#  Ruby 
#  Space 

doc.elements.each("*/section/book") { |e| puts e.attributes["isbn"] } 
# Output: 
#  0672328844 
#  0321445619 
#  0684835509 
#  074325631X 

sec2 = root.elements[2] 
author = sec2.elements[1].elements["author"].text    # Robert Zubrin 

有几个小细节需要留意:

  • XML中的属性被存储为一个哈希,所以用attributes["key"]就能取值。
  • 通过整数索引访问子元素时,REXML是从1开始计数的,不是0。

这一点在写遍历逻辑时要特别小心。

2. Stream Parsing(SAX-like)

当你面对的XML文件有几十上百兆时,树解析就不太合适了。因为内存会吃不住。

这时候就该流解析上场了。REXML提供了StreamListener模块,你只需要定义一个监听器类,然后在解析过程中回调相应的方法。

看个例子:

require 'rexml/document' 
require 'rexml/streamlistener' 
include REXML 

class MyListener 
  include REXML::StreamListener 
  def tag_start(*args) 
    puts "tag_start: #{args.map {|x| x.inspect}.join(', ')}" 
  end 

  def text(data) 
    return if data =~ /^w*$/   # whitespace only 
    abbrev = data[0..40] + (data.length > 40  "..." : "") 
    puts " text  :  #{abbrev.inspect}" 
  end 
end 

list = MyListener.new 
source = File.new "books.xml" 
Document.parse_stream(source, list) 

这段代码会依次输出每个标签的开始信息和文本内容。注意StreamListener提供的回调方法默认都是空的。

你只需要覆盖自己需要的那几个。输出效果大概如下:

tag_start: "library", {"shelf"=>"Recent Acquisitions"} 
tag_start: "section", {"name"=>"Ruby"} 
tag_start: "book", {"isbn"=>"0672328844"} 
tag_start: "title", {} 
 text  :  "The Ruby Way" 

这种方式的好处是内存占用几乎恒定,非常适合处理大型文档。

3. XPath

REXML还内置了对XPath的支持。你可以用非常简洁的路径表达式来定位节点。

比如:

book1 = XPath.first(doc, "//book")  # Info for first book found 
p book1 

# Print out all titles 
XPath.each(doc, "//title") { |e| puts e.text } 

# Get an array of all of the "author" elements in the document. 
names = XPath.match(doc, "//author").map {|x| x.text } 
p names 

运行结果:

 ...  
The Ruby Way 
The Case for Mars 
First Man: The Life of Neil A. Armstrong 
["Hal Fulton", "Robert Zubrin", "James R. Hansen"] 

XPath的强大之处在于它支持通配符、条件筛选等高级语法。

不过日常开发里,用//./基本就够用了。如果你经常写XML处理脚本,花五分钟熟悉一下XPath,回报率极高。

总结

总的来说,Builder和REXML的组合,覆盖了Ruby日常XML处理的绝大部分场景。

  • Builder负责创建XML。
  • REXML负责解析和查询XML。

创建、解析、查询,一套下来行云流水。

如果非要说有什么不足,那就是REXML的解析速度在超大文件面前不如Nokogiri。

但大多数情况下,它轻量、稳定、无需额外安装,已经足够了。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多