脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Ruby - Ruby中XML格式数据处理库REXML的使用方法指南

Ruby中XML格式数据处理库REXML的使用方法指南

2020-05-08 10:30David Mertz Ruby

这篇文章主要介绍了Ruby中XML格式数据处理库REXML的使用方法指南,值得注意的REXML库处理XML字符串时的编码问题,是需要的朋友可以参考下

以树方式使用 REXML
REXML 的目的是 正好够用。在最大程度上,它能很好地完成任务。 实际上, REXML 支持两种不同样式的 XML 处理 ― “树”和“流”。 第一种样式是 DOM 所尝试要做的更简单的版本;第二种样式是 SAX 所尝试要做的更简单的版本。 让我们先研究树样式。假设我们要提取上一个示例中的同一个地址簿文档。 下面的示例来自我所创建的经修改的 eval.rb ; 标准 eval.rb (链接到 Ruby 教程)可以根据对复杂对象的表达式求值显示非常长的计算结果 ― 我的 eval.rb 在没有错误发生的情况下不作出反应:
如何使用 REXML 来引用嵌套数据

?
1
2
3
4
5
6
ruby> require "rexml/document"
ruby> include REXML
ruby> addrbook = (Document.new File.new "address.xml").root
ruby> persons = addrbook.elements.to_a("//person")
ruby> puts persons[1].elements["address"].attributes["city"]
New York

这个表达式很普通。 .to_a() 方法创建文档中所有 <person> 元素的数组,在其它命名中它可能是有用的。 元素有点象 DOM 节点,但它其实更接近于 XML 本身(而且使用起来也更简单)。 .to_a() 的参数是 XPath,在这种情况下,可以标识文档中任何地方的所有 <person> 元素。如果我们只需要第一层上的元素,可以使用:
创建匹配元素的数组

?
1
ruby> persons = addrbook.elements.to_a("/addressbook/person")

我们甚至可以更直接地将 XPath 用作 .elements 属性的重载索引。例如:
使用 REXML 来引用嵌套数据的另一种方法

?
1
2
ruby> puts addrbook.elements["//person[2]/address"].attributes["city"]
New York

请注意,XPath 使用基于 1 的索引,不象 Ruby 和 Python 数组使用基于 0 的索引。换句话说, 它仍是我们正在检查其所在城市的同一个人。通过查看 REXML 请注意,XPath 使用基于 1 的索引,不象 Ruby 和 Python 数组使用基于 0 的索引。换句话说, 它仍是我们正在检查其所在城市的同一个人。通过查看
用 REXML 显示元素的 XML 源代码

?
1
2
3
4
5
6
7
ruby> puts addrbook.elements["//person[2]/address"]
<address city='New York' street='118 St.' number='344' state='NY'/>
ruby> puts addrbook.elements["//person[2]/contact-info"]
<contact-info>
 <email address='robb@iro.ibm.com'/>
 <home-phone number='03-3987873'/>
</contact-info>

此外,XPath 不必只与一个元素匹配。我们已在定义 persons 数组时看见过,但另一个示例强调了这一点:
将多个元素与 XPath 匹配

?
1
2
3
ruby> puts addrbook.elements.to_a("//person/address[@state='CA']")
<address city='Sacramento' street='Spruce Rd.' number='99' state='CA'/>
<address city='Los Angeles' street='Pine Rd.' number='1234' state='CA'/>

与此相反, .elements 属性的索引只产生 第一个匹配的元素:
当 XPath 只匹配第一次出现时

?
1
2
3
ruby> puts addrbook.elements.to_a("//person/address[@state='CA']")
<address city='Sacramento' street='Spruce Rd.' number='99' state='CA'/>
<address city='Los Angeles' street='Pine Rd.' number='1234' state='CA'/>

也可以通过 REXML 中的 XPath 类使用 XPath 地址, 它具有诸如 .first() 、 .each() 和 .match() 这样的方法。
REXML 元素的一个独特的惯用方法是 .each 迭代器。虽然 Ruby 有一个可对集合进行操作的循环结构 for , 但 Ruby 程序员通常更喜欢使用迭代器方法来将控制传递给代码块。下面的两种结构是等价的, 但第二种结构有更为自然的 Ruby 感觉:
通过在 REXML 中匹配 XPath 进行迭代

?
1
2
3
4
5
6
7
8
9
10
ruby> for addr in addrbook.elements.to_a("//address[@state='CA']")
  |  puts addr.attributes["city"]
  | end
Sacramento
Los Angeles
ruby> addrbook.elements.each("//address[@state='CA']") {
  |  |addr| puts addr.attributes["city"]
  | }
Sacramento
Los Angeles

以流方式使用 REXML
出于“正好够用”的目的, REXML 的树方式可能是 Ruby 语言最简单的方法。 但 REXML 还提供了一种流方式,它象是 SAX 的更轻量级的变体。 正如使用 SAX 一样, REXML 没有向应用程序程序员提供来自 XML 文档的缺省数据结构。 相反,“listener”或“handler”类负责提供响应文档流中各种事件的一组方法。 以下是常用集合:开始标记、结束标记、遇到的元素文本等等。
虽然流方式远远没有象以树方式工作那样容易,但通常它的速度要快很多。 REXML 教程声称流方式的速度要快 1500倍。 虽然我没有尝试过对它进行基准测试,但我猜想这是一种有限的情况(我的小示例在树方式中也是瞬间完成的)。 总之,如果速度要紧,那么速度上的差异很可能是显著的。
让我们研究一个非常简单的示例,它所做的事情与上面的“列出加州城市”示例相同。 对它进行扩展以用于复杂的文档处理相对比较简单:
REXML 中 XML 文档的流处理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ruby> require "rexml/document"
ruby> require "rexml/streamlistener"
ruby> include REXML
ruby> class Handler
  |  include StreamListener
  def tag_start name, attrs
  |    if name=="address" and attrs.assoc("state")[1]=="CA"
  |     puts attrs.assoc("city")[1]
  |    end
  end
  | end
ruby> Document.parse_stream((File.new "address.xml"), Handler.new)
Sacramento
Los Angeles

流处理示例中要注意的一件事情是,标记属性被作为一组数组传递, 它要处理的工作比起散列要稍微多一点(但可能在库中创建会更快)。

编码问题
REXML所有文本节点中都是以UTF-8编码的,所有调用的代码都要注意这一点,在程序中,传递给REXML的字符串必须是经过UTF-8编码的。

REXML不可能总是正确猜测出你的文本的编码方式,所以它总是假定为UTF-8编码。同时,如果你试图添加其他编码方式的文本,REXML不会发 出警告。添加者必须保证自己添加的是UTF-8的文本。如果添加标准的ASCII 7位编码,是没有关系的。如果使用ISO8859-1文本,必须在添加之前转换为UTF-8编码。可以使用text.unpack("C").pack("U")。变更编码进行输出,只有Document.write()和Document.to_s() 支持。如果需要输出特定编码的节点,必须用Output把输出对象包装起来。

?
1
2
3
4
e = Element.new "<a/>"
e.text = "f\xfcr"  # ISO-8859-1 '??'
o = ''
e.write( Output.new( o, "ISO-8859-1" ) )

可以向Output传递任何支持的编码。

延伸 · 阅读

精彩推荐
  • Ruby剖析 Ruby 访问控制

    剖析 Ruby 访问控制

    前面,我们说 Ruby 没有函数,只有方法.而且实际上有不止一种方法.这一节我们介绍 访问控制 (accesscontrols). 想想当我们在最高层而不是在一个类的定义里定义...

    ruby教程网3572020-04-08
  • RubyRuby迭代器的7种技巧分享

    Ruby迭代器的7种技巧分享

    这篇文章主要介绍了Ruby迭代器的7种技巧分享,Ruby中的迭代器非常人性化,本文既是讲解了7个技巧也是讲解了7种迭代器,需要的朋友可以参考下 ...

    脚本之家4782020-04-20
  • Ruby简要说明Ruby中的迭代器

    简要说明Ruby中的迭代器

    这篇文章主要介绍了Ruby中的迭代器,迭代器的概念在动态语言的编程中十分重要,文章中介绍了Ruby中的each迭代器和collect迭代器,需要的朋友可以参考下 ...

    goldensun2772020-04-25
  • RubyCentOS中配置Ruby on Rails环境

    CentOS中配置Ruby on Rails环境

    经过一个上午的折腾,终于把ROR环境在CentOS中搞定,绕了很多弯路,把文章写下来总结一下 ...

    可乐加糖4762020-04-12
  • RubyRuby进行文件信息输出实例代码

    Ruby进行文件信息输出实例代码

    Ruby进行文件信息输出实例代码,数据是随机的,所以每次的记录都会不同。 ...

    ruby教程网2962020-04-10
  • RubyRuby简洁学习笔记(一):字符串、数字、类和对象

    Ruby简洁学习笔记(一):字符串、数字、类和对象

    这篇文章主要介绍了Ruby简洁学习笔记(一):字符串、数字、类和对象,本文是学习笔记第一篇,需要的朋友可以参考下 ...

    脚本之家2472020-04-20
  • RubyRuby环境下安装使用bundler来管理多版本的gem

    Ruby环境下安装使用bundler来管理多版本的gem

    这篇文章主要介绍了Ruby环境下安装使用bundler来管理多版本的gem的方法,举了Ruby On Rails中的应用实例来进行演示,需要的朋友可以参考下 ...

    日拱一卒4332020-05-10
  • RubyRuby设计模式编程中使用Builder建造者模式的实例

    Ruby设计模式编程中使用Builder建造者模式的实例

    这篇文章主要介绍了Ruby设计模式编程中使用Builder建造者模式的实例,建造者模式将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表...

    范孝鹏2192020-05-07