|
在Java中使用DOM 和XPath 进行有效的XML处理--分析许多项目得到的启示和建议的代码广告 在Java中使用DOM 和XPath 进行有效的XML处理 --分析许多项目得到的启示和建议的代码
首席软件架构设计师, VelociGen Inc. 2001 年 12 月 在对几个大型 XML 项目分析的基础上,本文探讨了在 Java 中如何有效和高效的使用 DOM。DOM 为创建、处理和操纵
XML 文档提供了灵活和有效的方法,但使用起来可能比较困难并且可能会导致不稳定和错误的代码。作者 Parand Tony Daruger 提供了一套 Java
用法模式和函数库,使 DOM 变得健壮且易于使用。 正如我将在本文所演示的,当基于流的模型(例如 SAX)不能满足 XML 处理要求时,DOM 是一个极佳的选择。不幸的是,规范的几个方面,例如其语言无关性接口和“一切都是节点(everything-is-a-node)”抽象概念的使用,使其难以使用且易于生成脆弱代码。这在最近的几个大型 DOM 项目的研究中尤其明显,这些项目是由许多开发人员过去一年所创建的。下面讨论了常见的问题及其补救措施。 文档对象模型 该规范同样将文档的每个部分看成由类型和值组成的节点。这为处理文档的所有方面提供了完美的概念性框架。例如,下面的 XML 片段 the Italicized portion. 就是通过以下的 DOM 结构表示的: 图 1:XML 文档的 DOM 表示
完美的抽象确实付出了代价。考虑 XML 片段:Value。您或许会认为文本的值可以通过普通的 Java String 对象来表示,并且通过简单的 getValue 调用可访问。实际上,文本被当成 tagname 节点下的一个或多个子 Node。因此,为了获取文本值,您需要遍历 tagname 的子节点,将每个值整理成一个字符串。这样做有充分的理由:tagname 可能包含其它嵌入的 XML 元素,在这种情况下获取其文本值没有多大意义。然而,在现实世界中,我们看到由于缺乏便利的函数导致频繁的编码错误占了 80% 的情况,这样做的确有意义。 设计问题 DOM 使用“一切都是节点”的抽象。这就意味着几乎 XML 文档的每个部分,例如:Document、Element 和 Attr,全都继承(extend)Node 接口。这不仅是概念上完美,而且还允许每个 DOM 的不同实现通过标准接口使其自身的类可见,并且没有通过中间包装类所导致的性能损失。 由于存在的节点类型数量及其访问方法缺乏一致性,“一切都是节点”的抽象丧失了一些意义。例如, insertData 方法被用来设置 CharacterData 节点的值,而通过使用 setValue 方法来设置 Attr(属性)节点的值。由于对于不同的节点存在不同的接口,模型的一致性和完美性降低了,而学习曲线增加了。 JDOM 例如,JDOM 直接处理“一切都是节点”和 DOM 特定构造的使用(如 NodeList)。JDOM 将不同的节点类型(如 Document、Element 和 Attribute)定义为不同的 Java 类,这意味着开发者可以使用 new 构造它们,避免频繁类型转换的需要。JDOM 将字符串表示成 Java String,并且通过普通的 List 和 Iterator 类来表示节点的集合。(JDOM 用其本身类替代 DOM 类。) JDOM 为提供更完善的接口做了相当有益的工作。它已经被接受成为 JSR(正式的 Java Specification Request),而且它将来很可能会被包含到核心的 Java 平台中。但是,因其还不是核心 Java API 的一部分,一些人对于使用它还心存犹豫。这儿还有关于与 Iterator 和 Java 对象频繁创建相关的性能问题的报告。(请参阅参考资料)。 如果您对 JDOM 的接受性和可用性已经满足,并且如果您也没有将 Java 代码和程序员转移到其它语言的直接需求,JDOM 是个值得探索的好选择。JDOM 还不能满足本文探讨的项目所在的公司需要,因而他们使用了非常普遍的 DOM。本文也是这样做的。 常见编码问题 代码臃肿 遍历 DOM 清单 1 中,从根开始通过检索顶端元素遍历文档,获取其第一个子节点(configNode),并且最终单独检查 configNode 的子节点。不幸的是,这种方法不仅冗长,而且还伴随着脆弱性和潜在的错误。 例如,第二行代码通过使用 getFirstChild 方法获取中间的 config 节点。已经存在许多潜在的问题。根节点的第一个子节点实际上可能并不是用户正在搜索的节点。由于盲目地跟随第一个子节点,我忽视了标记的实际名称并且可能搜索不正确的文档部分。当源 XML 文档的根节点后包含空格或回车时,这种情况中发生一个频繁的错误;根节点的第一个子节点实际是 Node.TEXT_NODE 节点,而不是所希望的元素节点。您可以自己试验一下,从参考资料下载样本代码并且编辑 sample.xml 文件 — 在 sample 和 config 标记之间放置一个回车。代码立即异常而终止。要正确浏览所希望的节点,需要检查每个 root 的子节点,直到找到非 Text 的节点,并且那个节点有我正在查找的名称为止。 清单 1 还忽视了文档结构可能与我们期望有所不同的可能性。例如,如果 root 没有任何子节点,configNode 将会被设置为 null,并且示例的第三行将产生一个错误。因此,要正确浏览文档,不仅要单独检查每个子节点以及核对相应的名称,而且每步都得检查以确保每个方法调用返回的是一个有效值。编写能够处理任意输入的健壮、无错的代码,不仅需要非常关注细节,而且需要编写很多行代码。 最终,如果最初的开发者了解它的话,清单 1 中示例的所有功能应该可以通过利用对 getElementsByTagName 函数的简单调用实现。这是下面要讨论的。 检索元素中的文本值 sometagElement.getData(); 正如您所猜测到的,上面的代码并不会执行我们希望的动作。由于实际的文本被存储为一个或多个子节点,因此不能对 sometag 元素调用 getData 或类似的函数。更好的方法可能是: sometag.getFirstChild().getData(); 第二种尝试的问题在于值实际上可能并不包含在第一个子节点中;在 sometag 内可能会发现处理指令或其它嵌入的节点,或是文本值包含在几个子节点而不是单单一个子节点中。考虑到空格经常作为文本节点表示,因此对 sometag.getFirstChild() 的调用可能仅让您得到标记和值之间的回车。实际上,您需要遍历所有子节点,以核对 Node.TEXT_NODE 类型的节点,并且整理它们的值直到有完整的值为止。 注意,JDOM 已经利用便利的函数 getText 为我们解决了这个问题。DOM 级别 3 也将有一个使用规划的 getTextContent 方法的解答。教训:尽可能使用较高级的 API 是不会错的。 getElementsByTagName NodeList names = someElement.getElementsByTagName("name"); 将返回一个包含在 someElement 节点中称为 names 的节点 NodeList。这无疑比我所讨论的遍历方法更方便。这也是一组常见错误的原因。 问题在于 getElementsByTagName 递归地遍历文档,从而返回所有匹配的节点。假定您有一个包含客户信息、公司信息和产品信息的文档。所有这三个项中都可能含有 name 标记。如果调用 getElementsByTagName 搜索客户名称,您的程序极有可能行为失常,除了检索出客户名称,还会检索出产品和公司名称。在文档的子树上调用该函数可能会降低风险,但由于 XML 的灵活本质,使确保您所操作的子树包含您期望的结构,且没有您正在搜索的名称的虚假子节点就变得十分困难。 DOM 的有效使用 基本原则 不要使用 DOM 遍历文档。 这些原则直接从对常见问题的研究中得到。正如上面所讨论的,DOM 遍历是出错的主要原因。但它也是最常需要的功能之一。如何通过不使用 DOM 而遍历文档呢? XPath XPath 使用路径标记法来指定和匹配文档的各个部分,该标记法与文件系统和 URL 中使用的类似。例如,XPath:/x/y/z 搜索文档的根节点 x,其下存在节点 y,其下存在节点 z。该语句返回与指定路径结构匹配的所有节点。 更为复杂的匹配可能同时在包含文档的结构方面以及在节点及其属性的值中。语句 /x/y/* 返回父节点为 x 的 y 节点下的任何节点。/x/y[@name='a'] 匹配所有父节点为 x 的 y 节点,其属性称为 name,属性值为 a。请注意,XPath 处理筛选空格文本节点以获得实际的元素节点 — 它只返回元素节点。 详细探讨 XPath 及其用法超出了本文的范围。请参阅参考资料获得一些优秀教程的链接。花点时间学习 XPath,您将会更方便的处理 XML 文档。 函数库 要节省一些走弯路的时间,这里是一些将使您自己的库可以运转起来的基本助手函数。 findValue 通过同时传入要开始搜索的节点和指定要搜索节点的 XPath 语句来调用 findValue。函数查找第一个与给定 XPath 匹配的节点,并且抽取其文本值。 setValue appendNode 该函数的参数有:要将新节点添加到其下的节点,要添加的新节点名称,以及指定要将节点添加到其下位置的 XPath 语句(也就是,新节点的父节点应当是哪个)。新节点被添加到文档的指定位置。 最终分析 DOM 奠定了一个非常有效的基础,遵循一些简单的原则就可其上构建易于使用的系统。凝结了一大群用户智慧和经验的 DOM 未来版本正在设计之中,而且极有可能为这里讨论的问题提供解决方案。如 JDOM 这样的项目正在修改该 API 以获得更自然 Java 感觉,而且如本文中所述的技术可以帮助您使 XML 的操纵更方便、更简洁并且不易出错。利用这些项目且遵循这些用法模式以允许 DOM 成为基于 XML 项目的出色平台。 在论坛参与有关本文的讨论。 要获取有关的背景知识,参考由 W3C 维护的 DOM 规范。 下载和测试来自本文的样本代码。要运行代码,在您的 classpath 中需要 Xerces 和 Xalan。 从 Apache 项目下载 Xerces 和 Xalan DOM 以及 XPath 实现包。 使用 developerWorks 教程 理解 DOM 获得 DOM 的深入理解。 核对 JDOM 项目。 使用 developerWorks 文章 Simplify XML programming with JDOM 学习 JDOM 的使用技术。 使用 Zvon XPath Tutorial 加速 XPath 学习。 研究由 W3C 维护的 XPath 规范。 如果您想了解 IBM 的 WebSphere Application Server(WAS)是如何支持 XML 开发的,请参阅 WAS 高级版 3.5 在线帮助中有关 XML 的技术背景信息。 WebSphere Studio Application Developer 包含一个针对 XML
和 Java 的集成可视开发环境。在 WebSphere Developer Domain Studio 专区上获取更多信息。
如果您希望与本文章的作者或其所在机构,进一步交流,请联系:畅享网 姜小姐 jill.jiang@amteam.org | 021-51096826-112 | 在线联系 |
节能与优化IT 企业CIO过冬良策当前金融危机的影响还在继续漫延,很多企业都在苦寻过冬的良策,在这种情况下,节能与优化技术与产品无疑成为CIO们关注的首要对象,本次选题就是针对节能与优化IT来为CIO们提供过冬的良…… |
|
|