技巧: 轻量级 XML 库
--避免常用 API 的复杂性
David Mertz 博士(
mertz@gnosis.cx)
手势学家,Gnosis Software,Inc.
2002 年 3 月
在这篇技巧文章中,David 告诉您何时不使用重量级 XML API。诸如 SAX、DOM 和 XSLT 的标准 XML API
提供了转换和操纵 XML 文档的完善方法。但是其中的每一种都十分复杂,需要几百页规范文档和无数第三方书籍来加以说明和讲解。对于简单任务,有更简单的方法来完成
XML 工作。David 还提供了到许多轻量级 XML 库的链接,以及程序员该什么时候使用它们的指示。
XML
应该是容易的。它的承诺是:在不同平台和编程语言之间提供一种简单、直接和统一的数据交换方式。遗憾的是,用于操纵 XML 的最常见 API
一点也不简单。它们每一个都有几百页规范文档和相当陡峭的学习曲线。实际上,XML 本身也变得比其最初的承诺要复杂一些。应该有一种更容易的方法 —
事实上,的确有许多更简单的方法。
就其内部而言,这篇技巧文章中所指的大多数轻量级 API 被构建为(类)SAX 库的更高级别封装器。要使用高级别
API,程序员无需知道关于底层解析器的很多知识。从各个方面来说,简化的 API 只是为 XML 程序员进行处理提供了某些方便。
有两种使用轻量级 XML 库的一般方法。一种方法将 XML 转换成面向行的格式,人们熟悉的工具,如
wc、tail、head、uniq、grep、sed、awk — 和更复杂的方式,如 perl 和其它脚本语言 —
习惯于处理这种格式。另外一种方法是根据给定编程语言的“本机”数据结构使用表示 XML 文档的库。这种库可用于许多编程语言,它调用起来通常要比调用
DOM、XSLT 或 SAX 更简单(对于给定语言的程序员也更直观)。
面向行的 XML
PYX 格式是 XML 文档面向行的表示。PYX 本身不是
XML,但是它却能够表示 XML 文档内的信息。此外,需要时可以将 PYX 文档本身转换回 XML。在 PYX
中,每行的第一个字符标识该行的内容类型。前缀字符是:
PYX 前缀字符
( 开始标记
)
结束标记
A 属性
- 字符数据
? 处理指令
面向行的文本处理工具和技术的广泛使用和方便以及人们对它的熟悉推动了
PYX。这些工具通常期待新行分隔的记录,并且依靠正则表达式模式来识别文本的部分(奇匹配适合于 PYX 而不是 XML)。
PYX 库存在于几种编程语言,但是大多数时候,仅仅使用命令行工具 xmln(非验证)和
xmlv(验证)最有用。
同 XML 不同,PYX 格式允许您容易地对文档提出大量的特别问题。例如:样本文档中的所有属性值是什么?我们可以使用 PYX
简单地询问:
[PYX]# ./xmln test.xml | grep "^A" | awk '{print $2}'
或者,我们可以试图转储 XML 文档的非空内容行:
[PYX]# ./xmln test.xml | grep '^-[^\n ]' | sed s/^-//
可以使用 SAX 或 DOM
编写定制应用程序来完成上述询问,但是这样的查询的确值得成为一种一揽子解决方案。
本地化
DOM 的 API 方法使您能够访问表示 XML
文档的某个数据结构。问题是这个数据结构一点也不象编程语言内置的数据类型。许多库都向 XML 文档的“本地”版本发展。
Python 的 xml_objectify
当使用我自己的 Python 模块 xml_objectify
来读入 XML 文档时,您所得到的是一个非常简单的 Python
对象,其对象属性对应根文档元素的子元素和属性。子元素和标记属性之间的唯一区别是:它们是包含更多对象还是包含纯文本。测试(Python)属性所含内容的类型就足以确定它是作为子元素还是作为
XML 属性开始的。
请首先记住,您怎样才能使用 DOM 查看 XML 文档中的数据:
对 XML 数据结构的 Python DOM 访问
from xml.dom
import minidom
dom =
minidom.parse('test.xml')
print'flavor='+dom.childNodes[1].getAttribute('flavor')
print'PCDATA='+dom.childNodes[1].childNodes[5].childNodes[0].nodeValue
相比之下,xml_objectify 让用户以更直观、更 Python 化的方式引用 XML 文档数据:
对 XML 数据结构的 xml_objectify 访问
from
xml_objectify import XML_Objectify
py_obj =
XML_Objectify('test.xml').make_instance()
print 'flavor=' +
py_obj.flavor
print 'PCDATA=' + py_obj.MoreSpam.PCDATA
Ruby 的 REXML
REXML 库是以多模式运行的 Ruby 编程语言使用的库。流解析器以类似于 SAX
的方式工作,但是却有更面向 Ruby 的语法。树模式最有趣。基本上,这种模式十分类似于您使用 xml_objectify 或 Perl 的
XML::Parser“树”风格获取的数据表示。REXML 库的一个优点在于其类似 XPath 的区域指定器语法的集成。例如,REXML
教程显示这些行:
REXML 树模式解析和数据结构 require
"rexml/document"
include REXML
doc = Document.new
File.new("mydoc.xml")
doc.elements.each("inventory/section")
{
|element| puts element.attributes["name"] }
Java 的 JDOM
Java 也参与本地竞赛。尽管 DOM 本身的样式很象 Java,DOM
对编程语言保持中立的方法仍然不必很复杂(即便在 Java 中)。JDOM 是 XML 处理的更原始的 Java 版本。就让我们看一看 JDOM
任务语句来弄清这点:
没有令人信服的理由使操纵 XML 的 Java API 变得复杂、棘手、不直观或者头痛。JDOM 既是以 Java 为中心也是
Java 的优化。它的行为象 Java,它使用 Java 集合,对于目前的 Java 开发人员,它是完全自然的 API,它为使用 XML
提供了低成本入口点。
Perl 的 TMTOWTDI
在 Perl
编程语言的文化里,程序员们有一句格言:“做事情有不止一种方法。”这句口号很有名,以至于经常将其缩写为 TMTOWTDI。和您所期望的一样,Perl
开发人员提出了许多使用 XML 的不同方法。虽然确实存在支持如 DOM 和 SAX 等标准的 Perl 模块,但大多数 Perl 程序员却更喜欢体现 Perl
的主要优点(懒惰、傲慢及急躁)的模块。Perl 程序员认为,比起遵守严格、复杂的标准,他们可以做得更好、更快并且所需的工作也更少。
为了同其它编程语言的风格一致,树风格的 XML::Grove 和 XML::Parser 都将 XML 文档解析成非常 Perl
化的本地数据结构。
Haskell 的 HaXml
HaXml 本身很象 Haskell。它不一定简单,但是它却极其优雅。HaXml
极好地将函数编程风格带入了 XML 操纵。和讨论过的其它模块一样,HaXml 使 XML 文档看起来很象本地数据结构。
下面的示例快速地演示了如何才能进行到 HTML 的类 XSLT 转换:
输出易经 HTML 表的 HaXml 程序
module Main
where
import XmlLib
main = processXmlWith (hexagrams `o` tag
"IChing")
hexagrams =
html
[
hhead [htitle [keep /> tag "title" />
txt] ],
hbody [htableBorder [rows `o` children
`with` tag "hexagram"] ]
]
htableBorder = mkElemAttr
"TABLE" [("BORDER",("1"!))]
rows f = hrow [hcol [num], hcol [nam], hcol
[jdg]] f
where num = keep
/> tag "number" />
txt
nam = keep /> tag "name" />
txt
jdg = keep /> tag "judgement" /> txt
结束语
我建议您尝试这些轻量级库。对于您使用 XML
所做的许多普通工作,使用这些库都能完成得更快,并且更容易熟练掌握。即使您使用我没有讨论过的语言,请检查保存语言库的通常位置 —
那里可能有一些适合您的内容。
参考资料
关于 XML,您的确需要了解的内容在Extensible Markup Language
(XML) 1.0 W3C Recommendation里。当然,确切地理解这表示什么需要一点精明。
Pyxie
主页(Python PYX 库以及 xmlv 和 xmln 工具的 C 版本)由 Sourceforge 托管。
称为 XmlConnect
的项目的思想非常象 PYX。这两种格式大部分兼容(它们都从 SGML 的 ESIS 获得灵感)。
可以在
developerWorks 上找到我的描述 xml_objectify 的文章:
“XML Matters #2: On the 'Pythonic' treatment of XML documents as
objects(II)”(developerWorks 8 月,2000 年)
“XML Matters #11: Revisiting xml_pickle and xml_objectify”(developerWorks 6 月,2001 年)
请参阅Ruby
REXML 库主页。
也请参阅Java JDOM 库主页。
CPAN 托管 XML::Grove 模块的文档。
在 CPAN 上还可以找到 XML::Parser 模块的文档。
试用新的 IBM WebSphere Studio 开发环境,它可以轻而易举地生成动态电子商务应用程序。
关于作者
David Mertz 使用完全没有结构观念的头脑来撰写结构化文档格式。可以通过
mertz@gnosis.cx 和 David 联系,可以从 http://gnosis.cx/publish/
了解他的生活。
如果您希望与本文章的作者或其所在机构,进一步交流,请联系:畅享网 姜小姐
jill.jiang@amteam.org | 021-51096826-112 |
在线联系