以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 DTD/XML Schema 』  (http://bbs.xml.org.cn/list.asp?boardid=23)
----  对 XML 文档进行索引  (http://bbs.xml.org.cn/dispbbs.asp?boardid=23&rootid=&id=11928)


--  作者:anchen0617
--  发布时间:11/9/2004 3:24:00 PM

--  对 XML 文档进行索引
随着 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 的读者应该会发现其更深一层的专门化是相当简单的。我期待看到这些基本的索引类会对读者有所帮助


--  作者:hello105
--  发布时间:11/10/2004 12:32:00 PM

--  
路过
--  作者:sxhong
--  发布时间:11/11/2004 11:45:00 PM

--  
不怎么懂,到底怎样实现的又不说,好像只是工具的展示一样!能不能说一下是这样实现的,及实现思想
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
63.477ms