级别: 初级 David Mertz, Ph.D. (mertz@gnosis.cx), 对象专家, Gnosis Software, Inc.
2001 年 5 月 01 日 随着 XML 文档存储格式越来越普遍,特别对于面向散文文档,在 XML 文档集合中定位内容这一任务变得越发艰巨了。本专栏扩展了 David 在其“可爱的 Python #15”专栏中介绍的常规全文本索引器,使它包括了特定于 XML 的搜索和索引特性。本专栏讨论了该工具的设计是如何实现索引来利用 XML 的层次节点结构的优势的。
由数千页面组成的几兆字节的大型文档在企业和政府界中并不罕见。作家和技术人员例行公事般地创作出以
SGML(标准通用标记语言)格式表示的大量产品说明书、规章需求和计算机系统文档。从技术角度来说,XML
是简化和特殊化的 SGML。在这样一种近似性的前提下,XML
文档也应该是有效的 SGML 文档。
不过,从文化角度来说,XML 是从其它方面进化而来的。一方面,XML 是
EDI 的继任者。另一方面,它也是 HTML 的继任者。因为与 SGML
具有的文化历史背景不同,所以 XML
所经历的是其自身的工具开发过程。它变得越来越普遍,因此应该会看到越来越多的(通常)非正式的
HTML 文档和(通常)正式的 SGML 文档一起朝着 XML 格式的方向迁移 --
特别是使用例如 DocBook 这样的 XML 方言。
不过,在 XML 自身的文化中,它还没有培养出能够在大型 XML
文档中有效地定位内容的工具。象 UNIX 上的
grep
以及其它平台上类似工具等常规文件搜索工具完全可以读取 XML
文档的纯文本(除了可能存在的 Unicode 问题以外),但简单的
grep搜索(甚至复杂的 grep 搜索)会丢失 XML 文档的结构。
在搜索包含具有数千页面文档的文件内容时,您所知道的内容往往比可以在字、短语或规则表达式中指定的内容多得多。例如,到底那些农业报告中有哪些是
June Apple 小姐写的?象
grep
这样粗糙的工具通常会找到许多没有什么意义的事物。而且,象
grep
这样特别的工具虽然在它们执行任务时非常有效,但它们需要在每次执行搜索时检查大型文件的所有内容。如果是频繁的搜索,那么这种重复地搜索整个文件的方法,其效率是很低的。
扩展
indexer
根据上面所述的需要,我创建了公众域实用程序
xml_indexer 。这个 Python
模块可以用作运行时实用程序,也可以方便地由使用其服务的定制应用程序扩展。模块
xml_indexer 反过来依赖于我在以前 IBM developerWorks
文章中描述过的两个公众域实用程序的服务:
indexer 和
xml_objectify (请参阅
参考资料)。
xml_indexer 使用的“技巧”和 XPath
使用的“技巧”完全相同。不是将 XML
文档简单地作为文件系统中的“事物”对待,而是可以假装让 XML
文档中的层次节点看上去非常象是一个层次文件系统。为了索引,不需要一些语法将
XPath 和文件系统路径区分开来,而只是将 XML
节点作为它本身就是个文本文件来对待。幸运的是,我所设计的
indexer
有足够的灵活性,可以在索引文本中使用任意标识。让我们看一些搜索结果。
清单 1. 对 XML
节点执行的索引搜索
[D:\articles] indexer ibm
/articles/tutor/cryptology3.xml::/section[1]/panel[2]/body/text_column/p[1]
/temp/Benchmark/Data/addr2.xml::/person[4]/contact_info/email/@address
/temp/Benchmark/Data/addr2.xml::/person[2]/contact_info/email/@address
/tools/addr2.xml::/person[4]/contact_info/email/@address
/tools/addr2.xml::/person[2]/contact_info/email/@address
5 file matched wordlist: ['ibm']
Processed in 0.320 seconds (SlicedZPickleIndexer)
|
和使用 XPath 一样,
@ 标记位于属性值前,方括号中包含了编号的兄弟节点。到达 XML 文档的文件系统路径在这种上下文中充当 XPath 轴 -- 大体上类似于一个名称空间。为进行比较,让我们对文件数据库执行类似的索引搜索(使用了一些额外的搜索术语以使结果列表保持合理)。
清单 2.
电子邮件消息的索引搜索
[D:\articles] indexer ibm python xml indexer
D:\archive\mail\messages\tenco.cp15.2001-03-06.13+50+35
D:\archive\mail\messages\tenco.cp15.2001-03-01.07+57+26
D:\archive\mail\messages\tenco.cp15.2001-02-28.23+25+26
3 file matched wordlist: ['ibm', 'python', 'xml', 'indexer']
Processed in 2.530 seconds (SlicedZPickleIndexer)
|
第一个搜索是对相当少量的测试数据执行的,而第二个搜索则对大约
100MB
的归档电子邮件消息(存储在文件系统中,一条消息一个文件)使用“产品”索引。依我看,只花几秒钟的时间搜索
100MB 的文件(搜索多个同时出现的字)已经算得上非常快了。
而且,既然这些搜索利用了不同的索引数据库(因为在
xml_indexer
的测试阶段它们就已完成),没理由不创建文本文件和 XML
节点的复合索引。在这种情况下,甚至有可能(可能往往很有用)将每个
XML
文件
同时作为节点集合和文本文件来索引。这样做之后,搜索结果将显示标识的两种类型,很明显,在每次
XPath 在其名称空间中出现的场合中,文件系统标识都出现。清单 3
提供了一个示例。
清单 3.
电子邮件消息的索引搜索
[D:\articles] indexer actresses
/temp/Benchmark/Data/addr_break.xml
/temp/Benchmark/Data/addr_break.xml::/person[3]/misc_info
2 file matched wordlist: ['actresses']
Processed in 0.070 seconds (SlicedZPickleIndexer)
|
创建索引
读者会注意到上面的那些示例使用
indexer
执行搜索,而根本没有提到过
xml_indexer 。这是因为我可以使用完全相同的索引搜索工具来搜索由
xml_indexer 和
indexer
所创建的索引数据库。实际上,
indexer 只是对
python indexer.py ... 的调用,带有一些以适合于 OS
方式传递的命令行参数。您可以使用
indexer
来创建或增强文本文件索引(运行 '
indexer --help ' 或
'
indexer /? '
获得所需参数和开关的分类信息)。在向索引添加文件时,可以遍历目录。其它开关允许您将索引限于只添加其名称与模式(regex
或 glob)匹配的文件。
至少目前我可以使用简单一些的
xml_indexer.py
脚本来创建 XML
节点索引数据库。在写作本文的时候,我只能通过将文档名作为命令行参数指定,每次将单个
XML
文档的那些节点添加到索引数据库中。不过,在您读到这篇文章的时候,我可能已经增强了
xml_indexer.py 的命令行语法,使其看上去更类似于
indexer.py 的命令行语法。在使用它之前请先看一下
python xml_indexer.py --help 的输出。
指定 XPaths
为了向搜索结果提供 XPath 通配能力,我将一个
-filter
选项添加到
indexer 中,但在搜索结果中不支持 XPath
功能。这个选项有一个透明而有益的副作用,我可以对文件名“替换”使用同样的开关
-- 只是以防我只对匹配满足某些模式的文件感兴趣。
/filter 选项基本上可以照您希望的那样工作(为多个 shell 的不同引用语法进行了调整)。可以通过在过滤器中使用两个冒号来指定您只想获得 XPath 结果。
清单 4. 只返回 XPath
搜索结果
[D:\articles] indexer "/filter=*::*" actresses
/temp/Benchmark/Data/addr_break.xml::/person[3]/misc_info
1 file matched wordlist: ['actresses']
Processed in 0.050 seconds (SlicedZPickleIndexer)
|
清单 5. 只返回作为文件的
XML 文档
[D:\articles] indexer "/filter=*.xml" actresses
/temp/Benchmark/Data/addr_break.xml
1 file matched wordlist: ['actresses']
Processed in 0.050 seconds (SlicedZPickleIndexer)
|
标识为获得更为复杂的 XPath 指示符所需的子元素和顺序。
清单 6.
显示索引中的所有字匹配
[D:\articles] indexer symmetric
/tutor/cryptology1.xml::/section[2]/panel[8]/title
/tutor/cryptology1.xml::/section[2]/panel[8]/body/text_column/code_listing
/tutor/cryptology1.xml::/section[2]/panel[7]/title
/tutor/cryptology1.xml::/section[2]/panel[7]/body/text_column/p[1]
4 file matched wordlist: ['symmetric']
Processed in 0.100 seconds (SlicedZPickleIndexer)
|
清单 7. 将匹配限制在
title 元素中出现的内容
[D:\articles] indexer "-filter=*::/*/title" symmetric
/tutor/cryptology1.xml::/section[2]/panel[8]/title
/tutor/cryptology1.xml::/section[2]/panel[7]/title
2 file matched wordlist: ['symmetric']
Processed in 0.080 seconds (SlicedZPickleIndexer)
|
总结
xml_indexer 设计所得到的帮助大部分来自于反映在
indexer 设计中的面向对象原则。推翻
GenericIndexer 类(实际上,在其派生的
SlicedZPickleIndexer 中 --
但人们可以轻松地将任何具体的 Indexer
类混合进去)中的少许方法,这样就有可能使用全新的一组标识和数据源。
那些希望在自己比较大型 Python 项目中使用
xml_indexer 的读者应该会发现其更深一层的专门化是相当简单的。我期待看到这些基本的索引类会对读者有所帮助。
参考资料
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 可以
下载
xml_indexer 模块
。
- 可爱的 Python #15:
Developing a full-text indexer in Python 包含了有关
indexer 模块的常规背景讨论。
- 请参阅
indexer
模块
本身。
- 为了轻松地循环下降遍历 XML 节点,我利用了
xml_objectify 提供的高级 Python
化的接口。不过请注意,这一做法直到最近也不太实际。
xml_objectify
的较早版本使用 DOM 来读取 XML 文件,对于大型 XML
文档,它的处理速度缓慢得让人几乎无法忍受(部分归罪于
xml_objectify 处理该 DOM 所使用的方法)。Costas
Malamas 提供了一种替代语法分析方法,这种方法使用
expat
语法分析器和面向流技术。这种新技术对于某些复杂的 XML
文档来说仍然有些短暂的影响,但在大多数情况下都可以正常工作,而且速度快得多。可以联机找到
xml_objectify
。
- 通过仔细查看“IBM 认证开发者计划”的
XML
认证指导来提高您的 XML 技能。
- 参阅 David Mertz 以前的“XML 问题”专栏文章:
-
XML
问题 #1介绍 Python xml_pickle 对象。
-
XML
问题 #2描述如何使用 Python 的 xml_objectify。
-
XML
问题 #3介绍 DocBook。
-
XML
问题 #4继续介绍如何使用 DocBook 构建旧的文档档案。
-
XML
问题 #5说明如何通过 XSLT 将 XML 文档转换成 HTML。
-
XML
问题 #6 比较了半打 XML
编辑器,同时特别着眼于那些适合于有大量文本的文档的工具。
-
XML
问题 #7 将 DTD 与 XML Schema 进行了权衡,并建议无论 W3C XML
Schema 规范有多么成熟,开发者在什么情况下需要坚持使用 DTD。
-
XML
话题 #8
讨论了由计算机科学家概念化的数据
模型的抽象理论是如何帮助我们开发一些特殊的多表示的数据流。
-
XML
话题 #9 讨论了公众域 sql2dtd 和 sql2xml
实用程序;这些实用程序可以不依赖 RDBMS 生成可移植 XML 结果集。
关于作者
对本文的评价
|