对于 XML 处理,至少可以采取两种态度。一种是采用可以从许多编程语言调用的标准 API。第二种是修改 XML 处理库以适应正用于开发 XML 应用程序的编程语言的特定功能。 在本专栏的前几篇文章中,David 研究了使用他自己的 Python
xml_pickle
和 xml_objectify
库以及 Haskell HaXml
库的第二种方法的多个版本。相当新、但发展很快的 Ruby 编程语言的常用库也采用第二种方法。 这里,David 介绍了 Ruby Electric XML( REXML
),这种库采用 Ruby 的长处,并围绕它们构建 XML 处理。 REXML
具有类似于 SAX 的流样式和 DOM 的树样式的 API,但没有直接将它本身限制于这两种 API。
首先,让我介绍一下 Ruby 语言。这里,我不能完全保证能使不熟悉 Ruby 的读 者快速掌握这种语言 ― 既然如此,我建议参阅 参考资料中 的文章。 但我自己作为一名学习 Ruby 语言的程序员,我可以让您了解它为什么很有趣。 Ruby 是一种脚本语言,曾经被描述为“更好的 Perl”。此外,每一种更新的脚本语言可能也都被这样描述过,包括 Python。 当从完全 Smalltalk 式的 OOP 态度来看,对于 Ruby,描述变得更为确切,不是说 Perl 出了什么错(这是没有对某种语言的攻击),而是说 Ruby 保留了 Perl 的许多简明性及其许多捷径。 而且(至少对我而言),Ruby 达到了简明性, 而且还避免了在某些 Perl 代码中发现的“可执行行噪声”质量问题。同时, 与 Python 版本相比,许多 Ruby 结构“感觉”更直接(即使它们并没有真正节省太多总体长度)。
REXML
是由 Sean Russell 编写的库。它不是 Ruby 的唯一 XML 库,但它是很受欢迎的一个,并且是用纯 Ruby 编写( NQXML
也是用 Ruby 编写的, 但 XMLParser
封装了用 C 编写的 Jade 库)。 在他的 REXML 概述中,Russell 评论道:
我 有这样的问题:我不喜欢令人困惑的 API。有几种用于 Java 实现的 XML 解析器 API。其中大多数都遵循 DOM 或 SAX,并且在基本原理上与不断出现的众多 Java API 非常相似。也就是说,它们看 上去象是由从未使用过他们自己的 API 的理论家设计出来的。 通常,现有的 XML API 都很令人讨厌。他们采用一种被明确设计成非常简单、一流且功能强大的标记语言, 然后用讨厌的、过多的和大型 API 对它进行封装。甚至是为了进行最基本的 XML 树操作,我总是不得不参考 API 文档; 没有任何东西是凭直觉的,而且几乎每个操作都很复杂。
虽然我并不认为它有多么令人心烦,但我同意 Russell 的观点:XML API 对于大多数使用它们的人来说无疑带来了过多的工作量。
我猜想处理 XML 文档的所有程序员中有 80% 真正需要的只是一种提取数据并 将它们作为结构化的数据容易地进行操作的方法。DOM 使这一事情变得困难,而 SAX 使 它变得更困难。在前几篇文章中,我提倡我自己的 Python xml_objectify
模块的清晰性和简明性。让我使用文件 address.xml
(它描述一个地址簿)来快速重复一个示例。
如何使用 xml_objectify 来引用嵌套数据
>>> from xml_objectify import XML_Objectify |
我们需要略微知道一点数据的格式……但不必很多(有关本文中使用的样本文档, 请参阅 参考资料)。我们需要知道文档的根元素是地址 簿(但它的名称不必是
<addressbook></addressbook>
)。而且我们需要知道该文档可以列出多人(但是,如果只有一个人, 他可以作为 addressbook.person
或 addressbook.person[0]
来引用,那样也不会发生错误)。 从概念上讲,还需要知道人有地址,地址有城市。 知道这些就够用了!
相反,DOM ― 它将其本身标榜为 OOP 化的 XML ― 却要我们完成所有的操作步骤。第一个难题涉及根元素; 要完成这个任务至少有五种不同的方法可以想到:
使用 DOM 来命名 XML 文档根元素
>>> from xml.dom import minidom |
您还必须对究竟什么是方法、什么是属性做一些猜测(或在手边放一本手册)。 假设我们知道需要根元素,则 ._get_documentElement()
方法可能 是最好的选择。现在,如果我们想要向下找到第二个人的城市,就象 xml_objectify
示例中那样,应该怎么做呢?
如何使用 DOM 来引用嵌套数据
>>> addressbook = dom._get_documentElement() |
这种样式相当冗长,但或许是最接近的 DOM 等价样式。 您可以直接使用 .childNodes
属性数组来保存一些字符, 但这种样式是脆弱的,例如,如果
<addressbook></addressbook>
有子元素, 而
<person></person>
没有的话。您还必须知道一些本质细节, city
是元素属性,而不是子标记内容(任何一种方法都可能对正在讨论的基本数据有意义)。
REXML
的目的是 正好够用。在最大程度上,它能很好地完成任务。 实际上, REXML
支持两种不同样式的 XML 处理 ― “树”和“流”。 第一种样式是 DOM 所尝试要做的更简单的版本;第二种样式是 SAX 所尝试要做的更简单的版本。 让我们先研究树样式。假设我们要提取上一个示例中的同一个地址簿文档。 下面的示例来自我所创建的经修改的 eval.rb
; 标准 eval.rb
(链接到 Ruby 教程)可以根据对复杂对象的表达式求值显示非常长的计算结果 ― 我的 eval.rb 在没有错误发生的情况下不作出反应:
如何使用 REXML 来引用嵌套数据
ruby> require "rexml/document" |
这个表达式很普通。 .to_a()
方法创建文档中所有
<person></person>
元素的数组,在其它命名中它可能是有用的。 元素有点象 DOM 节点,但它其实更接近于 XML 本身(而且使用起来也更简单)。 .to_a()
的参数是 XPath,在这种情况下,可以标识文档中任何地方的所有
<person></person>
元素。如果我们只需要第一层上的元素,可以使用:
创建匹配元素的数组
ruby> persons = addrbook.elements.to_a("/addressbook/person") |
我们甚至可以更直接地将 XPath 用作 .elements
属性的重载索引。例如:
使用 REXML 来引用嵌套数据的另一种方法
ruby> puts addrbook.elements["//person[2]/address"].attributes["city"] |
请注意,XPath 使用基于 1 的索引,不象 Ruby 和 Python 数组使用基于 0 的索引。换句话说, 它仍是我们正在检查其所在城市的同一个人。通过查看 REXML
请注意,XPath 使用基于 1 的索引,不象 Ruby 和 Python 数组使用基于 0 的索引。换句话说, 它仍是我们正在检查其所在城市的同一个人。通过查看
用 REXML 显示元素的 XML 源代码
ruby> puts addrbook.elements["//person[2]/address"] |
此外,XPath 不必只与一个元素匹配。我们已在定义 persons
数组时看见过,但另一个示例强调了这一点:
将多个元素与 XPath 匹配
ruby> puts addrbook.elements.to_a("//person/address[@state='CA']") |
与此相反, .elements
属性的索引只产生 第一个匹配的元素:
当 XPath 只匹配第一次出现时
ruby> puts addrbook.elements["//person/address[@state='CA']"] |
也可以通过 REXML
中的 XPath
类使用 XPath 地址, 它具有诸如 .first()
、 .each()
和 .match()
这样的方法。
REXML
元素的一个独特的惯用方法是 .each
迭代器。虽然 Ruby 有一个可对集合进行操作的循环结构 for
, 但 Ruby 程序员通常更喜欢使用迭代器方法来将控制传递给代码块。下面的两种结构是等价的, 但第二种结构有更为自然的 Ruby 感觉:
通过在 REXML 中匹配 XPath 进行迭代
ruby> for addr in addrbook.elements.to_a("//address[@state='CA']") |
出于“正好够用”的目的, REXML
的树方式可能是 Ruby 语言最简单的方法。 但 REXML
还提供了一种流方式,它象是 SAX 的更轻量级的变体。 正如使用 SAX 一样, REXML
没有向应用程序程序员提供来自 XML 文档的缺省数据结构。 相反,“listener”或“handler”类负责提供响应文档流中各种事件的一组方法。 以下是常用集合:开始标记、结束标记、遇到的元素文本等等。
虽然流方式远远没有象以树方式工作那样容易,但通常它的速度要快很多。 REXML
教程声称流方式的速度要快 1500倍。 虽然我没有尝试过对它进行基准测试,但我猜想这是一种有限的情况(我的小示例在树方式中也是瞬间完成的)。 总之,如果速度要紧,那么速度上的差异很可能是显著的。
让我们研究一个非常简单的示例,它所做的事情与上面的“列出加州城市”示例相同。 对它进行扩展以用于复杂的文档处理相对比较简单:
REXML 中 XML 文档的流处理
ruby> require "rexml/document" |
流处理示例中要注意的一件事情是,标记属性被作为一组数组传递, 它要处理的工作比起散列要稍微多一点(但可能在库中创建会更快)。
这篇文章研究了另外一种比起 DOM、SAX 和 XSLT 麻烦的 API 更轻量级的替代方法。 连同前几篇文章中研究的 xml_objectify
、PYX 和 HaXml
选项一起,Ruby 程序员还得到了一种处理 XML 的快速方法,而不必经历陡峭的学习曲线。
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文.
- Maya Stodte 为 IBM developerWorks 编写了 Ruby 简介,但已经过了两年,Ruby 在这段时间内已有一定的发展。
- Joshua Drake 也编写了一篇描述一些 基本 Ruby 结构的较新文章。
- 幸运的是,Ruby 在其网站上有一个极好的 教程。 语言参考和其它文档也值得一读。
- 我还阅读了 O'Reilly 出版的题为 Ruby in a Nutshell的 书籍, 由 Ruby 创建人 Yukihiro Matsumoto 所著。作为一名学习 Ruby 的程序员,我承认: 这本书很适合我,但可能不太适合更有经验的 Ruby 用户。 尽管如此,我仍认为这本书“没有被十分完整翻译”(原著是用日文写的)。 虽然作为参考这本书组织得很好,但有许多描述仍让我无法确定语言中那些偶尔的微妙之处。
- REXML 主页包含一个非常好的教程, 它并不完整,但它可以很好地帮助您尽快熟悉。
- 请访问有关 Ruby 和 XML 的新闻和讨论的 网站。
- 可以从 http://gnosis.cx/download/address.xml找到本文中使用的地址簿示例。
- 最后,请了解一下 IBM WebSphere Studio Application Developer, 这是一个易于使用的集成开发环境,可用于构建、测试和部署 J2EE 应用程序,包括从 DTD 和模式生成 XML 文档。
相关推荐
Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门...
在压缩包"ruby-master"中,可能包含的是Ruby的源码仓库或者教程资料。通常,"master"分支代表了项目的主分支,里面可能有Ruby的示例代码、教程文档、测试用例等。通过学习这些内容,你可以深入理解Ruby的语法特性,...
Ruby编程语言[www.TopSage.com].pdf
本书详细介绍了Ruby 1.8和1.9版本各方面的内容。... 本书还包含对Ruby平台上丰富的API的详尽介绍,并用带有详尽注释的代码演示了Ruby进行文本处理、数字运算、集合、输入/输出、网络开发和并发编程的功能。
### Ruby编程语言核心知识点解析 #### 一、书籍概述与作者背景 《The Book of Ruby》是由Huzaifa Sidhpurwala与Huw Collingbourne两位专家共同编著的一本深入探讨Ruby编程语言的书籍。该书不仅适用于Ruby编程初学...
[Ruby编程语言].David.Flanagan等
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
松本行弘原著,Ruby编程入门非常好的书籍。共两个文件
Ruby是一种动态、面向对象的编程语言,而Selenium WebDriver是一个开源的自动化测试框架,支持多种浏览器和编程语言,其中包括Ruby。在这个“ruby+selenium-webdriver测试--第一个例子源代码”中,我们将探讨如何...
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
Ruby是一种跨平台、面向对象的动态类型编程语言。Ruby 体现了表达的一致性和简单性,它不仅是一门编程语言,更是表达想法的一种简练方式。 Ruby 是一个注重均衡的语言,它的发明者松本行弘(Yukihiro “Matz” ...
内容概要:本文详细介绍了Ruby编程语言中的基础和高级控制结构,包括条件语句(if、unless)、循环语句(while、until、for)、迭代器(each、map、select),以及模式匹配(case)、跳转控制(next、retry、break、...
### Ruby编程语言简介 #### 一、Ruby编程语言概述 Ruby是一种动态的、面向对象的、通用型的编程语言,自1995年由日本程序员松本行弘(Yukihiro Matsumoto)创建以来,便以其简洁优雅的语法、高度可读性和易于学习...
Ruby-Savon是Ruby编程语言中的一个强大的SOAP(Simple Object Access Protocol)客户端库,它使得在Ruby中与SOAP服务交互变得简单而高效。SOAP是一种基于XML的协议,用于在不同系统之间交换结构化和类型化的数据,常...
Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro "Matz" Matsumoto于1995年创建。它的设计目标是让编程变得更加简洁、优雅,强调代码的可读性和开发者的生产力。Ruby 1.9.1是该语言的一个重要版本,引入了...
Ruby编程语言,由日本程序员松本行弘于1995年开发,是一种面向对象、动态类型的语言,设计时强调简洁、优雅和可读性。它融合了多种编程范式,包括面向对象、函数式、命令式和反射,使得Ruby在处理复杂任务时具有极高...
Ruby编程语言,是一种面向对象的、动态类型的脚本语言,由日本人松本行弘于1995年设计并开发。它以其简洁、优雅的语法和强大的功能深受开发者喜爱,尤其在Web开发领域,Ruby on Rails框架的出现,极大地推动了Ruby的...