`
glinuz
  • 浏览: 18417 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

Ruby 编程语言中的 XML 处理--转载

    博客分类:
  • ruby
阅读更多
原文连接:http://www.ibm.com/developerworks/cn/xml/x-matters/part18/index.html
对于 XML 处理,至少可以采取两种态度。一种是采用可以从许多编程语言调用的标准 API。第二种是修改 XML 处理库以适应正用于开发 XML 应用程序的编程语言的特定功能。 在本专栏的前几篇文章中,David 研究了使用他自己的 Python xml_picklexml_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 = XML_Objectify('address.xml').make_instance()
>>> print addressbook.person[1].address.city
New York

我们需要略微知道一点数据的格式……但不必很多(有关本文中使用的样本文档, 请参阅 参考资料)。我们需要知道文档的根元素是地址 簿(但它的名称不必是 <addressbook></addressbook> )。而且我们需要知道该文档可以列出多人(但是,如果只有一个人, 他可以作为 addressbook.personaddressbook.person[0] 来引用,那样也不会发生错误)。 从概念上讲,还需要知道人有地址,地址有城市。 知道这些就够用了

相反,DOM ― 它将其本身标榜为 OOP 化的 XML ― 却要我们完成所有的操作步骤。第一个难题涉及根元素; 要完成这个任务至少有五种不同的方法可以想到:



使用 DOM 来命名 XML 文档根元素
>>> from xml.dom import minidom
>>> dom = minidom.parse('address.xml')
>>> dom.firstChild
<dom at="" addressbook="" element:="">
>>> dom._get_documentElement()
<dom at="" addressbook="" element:="">
>>> dom._get_firstChild()
<dom at="" addressbook="" element:="">
>>> dom.getElementsByTagName('addressbook')[0]
<dom at="" addressbook="" element:="">
>>> dom.childNodes[0]
<dom at="" addressbook="" element:="">
</dom></dom></dom></dom></dom>

您还必须对究竟什么是方法、什么是属性做一些猜测(或在手边放一本手册)。 假设我们知道需要根元素,则 ._get_documentElement() 方法可能 是最好的选择。现在,如果我们想要向下找到第二个人的城市,就象 xml_objectify 示例中那样,应该怎么做呢?



如何使用 DOM 来引用嵌套数据
>>> addressbook = dom._get_documentElement()
>>> print addressbook.getElementsByTagName('person')[1].\
.. getElementsByTagName('address')[0].getAttribute('city')
New York

这种样式相当冗长,但或许是最接近的 DOM 等价样式。 您可以直接使用 .childNodes 属性数组来保存一些字符, 但这种样式是脆弱的,例如,如果 <addressbook></addressbook> 有子元素, 而 <person></person> 没有的话。您还必须知道一些本质细节, city 是元素属性,而不是子标记内容(任何一种方法都可能对正在讨论的基本数据有意义)。



 

以树方式使用 REXML

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



如何使用 REXML 来引用嵌套数据
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></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"]
New York

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



用 REXML 显示元素的 XML 源代码
ruby> puts addrbook.elements["//person[2]/address"]

ruby> puts addrbook.elements["//person[2]/contact-info"]
<contact-info>
<email address="robb@iro.ibm.com">
<home-phone number="03-3987873">
</home-phone></email></contact-info>

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



将多个元素与 XPath 匹配
ruby> puts addrbook.elements.to_a("//person/address[@state='CA']")



与此相反, .elements 属性的索引只产生 第一个匹配的元素:



当 XPath 只匹配第一次出现时
ruby> puts addrbook.elements["//person/address[@state='CA']"]

ruby> puts addrbook.elements.to_a("//person/address[@state='CA']")[0]
 

也可以通过 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']")
| 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 文档的流处理
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

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




结束语

这篇文章研究了另外一种比起 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编程语言入门与实践 .pptx

    Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门与实践 Ruby编程语言入门...

    基于Ruby编程语言基于Ruby编程语言基于Ruby编程语言基于Ruby编程语言.zip

    在压缩包"ruby-master"中,可能包含的是Ruby的源码仓库或者教程资料。通常,"master"分支代表了项目的主分支,里面可能有Ruby的示例代码、教程文档、测试用例等。通过学习这些内容,你可以深入理解Ruby的语法特性,...

    Ruby编程语言pdf版

    Ruby编程语言[www.TopSage.com].pdf

    Ruby编程语言pdf

    本书详细介绍了Ruby 1.8和1.9版本各方面的内容。... 本书还包含对Ruby平台上丰富的API的详尽介绍,并用带有详尽注释的代码演示了Ruby进行文本处理、数字运算、集合、输入/输出、网络开发和并发编程的功能。

    Ruby 编程语言的书籍

    ### Ruby编程语言核心知识点解析 #### 一、书籍概述与作者背景 《The Book of Ruby》是由Huzaifa Sidhpurwala与Huw Collingbourne两位专家共同编著的一本深入探讨Ruby编程语言的书籍。该书不仅适用于Ruby编程初学...

    [Ruby编程语言].David.Flanagan等

    [Ruby编程语言].David.Flanagan等

    ruby安装包-rubyinstaller-devkit-3.0.2-1-x64安装文件

    Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...

    Ruby编程语言中文版

    松本行弘原著,Ruby编程入门非常好的书籍。共两个文件

    ruby+selenium-webdriver测试--第一个例子源代码

    Ruby是一种动态、面向对象的编程语言,而Selenium WebDriver是一个开源的自动化测试框架,支持多种浏览器和编程语言,其中包括Ruby。在这个“ruby+selenium-webdriver测试--第一个例子源代码”中,我们将探讨如何...

    ruby安装包-rubyinstaller-devkit-3.0.2-1-x64.zip

    Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...

    Ruby动态编程语言v2.6.3

    Ruby是一种跨平台、面向对象的动态类型编程语言。Ruby 体现了表达的一致性和简单性,它不仅是一门编程语言,更是表达想法的一种简练方式。 Ruby 是一个注重均衡的语言,它的发明者松本行弘(Yukihiro “Matz” ...

    Ruby编程语言中基础和高级控制结构详解

    内容概要:本文详细介绍了Ruby编程语言中的基础和高级控制结构,包括条件语句(if、unless)、循环语句(while、until、for)、迭代器(each、map、select),以及模式匹配(case)、跳转控制(next、retry、break、...

    Ruby编程,Ruby编程,

    ### Ruby编程语言简介 #### 一、Ruby编程语言概述 Ruby是一种动态的、面向对象的、通用型的编程语言,自1995年由日本程序员松本行弘(Yukihiro Matsumoto)创建以来,便以其简洁优雅的语法、高度可读性和易于学习...

    Ruby-Savon是一个Ruby编程语言的SOAP客户端

    Ruby-Savon是Ruby编程语言中的一个强大的SOAP(Simple Object Access Protocol)客户端库,它使得在Ruby中与SOAP服务交互变得简单而高效。SOAP是一种基于XML的协议,用于在不同系统之间交换结构化和类型化的数据,常...

    ruby-1.9.1-p0-i386-mswin32.rar

    Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro "Matz" Matsumoto于1995年创建。它的设计目标是让编程变得更加简洁、优雅,强调代码的可读性和开发者的生产力。Ruby 1.9.1是该语言的一个重要版本,引入了...

    Ruby编程语言算法集

    Ruby编程语言,由日本程序员松本行弘于1995年开发,是一种面向对象、动态类型的语言,设计时强调简洁、优雅和可读性。它融合了多种编程范式,包括面向对象、函数式、命令式和反射,使得Ruby在处理复杂任务时具有极高...

    Ruby编程语言教学资源压缩包

    Ruby编程语言,是一种面向对象的、动态类型的脚本语言,由日本人松本行弘于1995年设计并开发。它以其简洁、优雅的语法和强大的功能深受开发者喜爱,尤其在Web开发领域,Ruby on Rails框架的出现,极大地推动了Ruby的...

Global site tag (gtag.js) - Google Analytics