




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java 中的 XML: Java 文档模型的用法简要探讨 Java 中不同 XML 文档模型的工作原理Dennis M. Sosnoski (), 总裁, Sosnoski Software Solutions, Inc.Dennis Sosnoski 是西雅图地区 Java 咨询公司 Sosnoski Software Solutions, Inc.的创始人和首席顾问,他是 J2EE、XML 和 Web 服务支持方面的专家。他已经有 30 多年专业软件开发经验,最近几年他集中研究服务器端的 Java 技术。Dennis 经常在全国性的会议上就 XML 和 Java 技术发表演讲,您可以通过 与 Dennis 联系。简介:本文中,XML 工具观察家 Dennis Sosnoski 对比了几种 Java 文档模型的可用性。当选取一种模型时并不总是很清楚有哪些折衷,而且如果您稍后改了主意,那么可能需要进行大量重新编码工作才能转换。作者将样本代码与模型 API 的分析相结合,对哪些模型可能真正使您的工作方便给出了建议。本文包含显示五种不同文档模型的方法的代码样本。标记本文!发布日期:2002 年 2 月 01 日 级别:初级 访问情况178 次浏览 建议:0(添加评论) 平均分 (共 0 个评分 )在本系列的第一篇文章中,我研究了一些用 Java 编写的主要的 XML 文档模型的性能。但是,在开始选择这种类型的技术时,性能只是问题的一部分。使用方便至少是同样重要的,并且它已是一个主要理由,来支持使用 Java 特定的模型,而不是与语言无关的 DOM 。为切实了解哪个模型真正的作用,您需要知道它们在可用性程度上是如何排名的。本文中,我将尝试进行这个工作,从样本代码开始,来演示如何在每个模型中编码公共类型的操作。并对结果进行总结来结束本文,而且提出了促使一种表示比另一种更容易使用的一些其它因素。请参阅以前的文章(请参阅 参考资料或本文“内容”下的便捷链接)来获取这个对比中使用的各个模型的背景资料,包含实际的版本号。还可以参阅“参考资料”一节中关于源代码下载、到模型主页的链接以及其它相关信息。 代码对比在对不同文档表示中用法技术的这些对比中,我将显示如何在每种模型中实现三种基本操作: 根据输入流构建文档 遍历元素和内容,并做一些更改: o 从文本内容中除去前导和尾随的空白。 o 如果结果文本内容为空,就删除它。 o 否则,将它包装到父元素的名称空间中一个名为“text”的新元素中。 将已修改的文档写入输出流 这些示例的代码是以我在上篇文章中使用的基准程序为基础的,并进行了一些简化。基准程序的焦点是为了显示每个模型的最佳性能;对于本文,我将尝试显示在每种模型中实现操作的最简便方法。我已经将每个模型的示例结构化为两个独立的代码段。第一段是读取文档、调用修改代码和编写已修改文档的代码。第二段是真正遍历文档表示和执行修改的递归方法。为避免分散注意力,我已在代码中忽略了异常处理。您可以从本页底部 参考资料一节链接到下载页,以获取所有样本的完整代码。样本的下载版本包括一个测试驱动程序,还有一些添加的代码用于通过计算元素、删除和添加的个数来检查不同模型的操作。 即使您不想使用 DOM 实现,但还是值得浏览下面对 DOM 用法的描述。因为 DOM 示例是第一个示例,所以与后面的模型相比,我用它来探究有关该示例的一些问题和结构的更详细信息。浏览这些内容可以补充您想知道的一些细节,如果直接阅读其它模型之一,那么将错过这些细节。回页首DOMDOM 规范涵盖了文档表示的所有类型的操作,但是它没有涉及例如对文档的语法分析和生成文本输出这样的问题。包括在性能测试中的两种 DOM 实现,Xerces 和 Crimson,对这些操作使用不同的技术。清单 1 显示了 Xerces 的顶级代码的一种形式。清单 1. Xerces DOM 顶级代码 1 / parse the document from input stream (in) 2 DOMParser parser = new DOMParser(); 3 parser.setFeature(/sax/features/namespaces, true); 4 parser.parse(new InputSource(in); 5 Document doc = parser.getDocument(); 6 / recursively walk and modify document 7 modifyElement(doc.getDocumentElement(); 8 / write the document to output stream (out) 9 OutputFormat format = new OutputFormat(doc);10 XMLSerializer serializer = new XMLSerializer(out, format);11 serializer.serialize(doc.getDocumentElement();正如我在注释中指出的,清单 1 中的第一块代码(第 1-5 行)处理对输入流的语法分析,以构建文档表示。Xerces 定义了 DOMParser 类,以便从 Xerces 语法分析器的输出构建文档。 InputSource 类是 SAX 规范的一部分,它能适应供 SAX 分析器使用的几种输入形式的任何之一。通过单一调用进行实际的语法分析和文档构造,如果成功完成了这一操作,那么应用程序就可以检索并使用已构造的 Document 。 第二个代码块(第 6-7 行)只是将文档的根元素传递给我马上要谈到的递归修改方法。这些代码与本文中所有文档模型的代码在本质上是相同的,所以在剩余的示例中我将跳过它,不再做任何讨论。第三个代码块(第 8-11 行)处理将文档作为文本写入输出流。这里, OutputFormat 类包装文档,并为格式化生成的文本提供了多种选项。 XMLSerializer 类处理输出文本的实际生成。 Xerces 的 modify 方法只使用标准 DOM 接口,所以它还与任何其它 DOM 实现兼容。清单 2 显示了代码。清单 2. DOM Modify 方法 1 protected void modifyElement(Element element) 2 / loop through child nodes 3 Node child; 4 Node next = (Node)element.getFirstChild(); 5 while (child = next) != null) 6 / set next before we change anything 7 next = child.getNextSibling(); 8 / handle child by node type 9 if (child.getNodeType() = Node.TEXT_NODE) 10 / trim whitespace from content text11 String trimmed = child.getNodeValue().trim();12 if (trimmed.length() = 0) 13 / delete child if nothing but whitespace14 element.removeChild(child);15 else 16 / create a text element matching parent namespace17 Document doc = element.getOwnerDocument();18 String prefix = element.getPrefix();19 String name = (prefix = null) ? text : (prefix + :text);20 Element text = 21 doc.createElementNS(element.getNamespaceURI(), name);22 / wrap the trimmed content with new element23 text.appendChild(doc.createTextNode(trimmed);24 element.replaceChild(text, child);25 26 else if (child.getNodeType() = Node.ELEMENT_NODE) 27 / handle child elements with recursive call28 modifyElement(Element)child);29 30 31 清单 2 中显示的方法所使用的基本方法与所有文档表示的方法相同。 通过一个元素调用它,它就依次遍历那个元素的子元素。如果找到文本内容子元素,要么删除文本(如果它只是由空格组成的),要么通过与包含元素相同的名称空间中名为“text”的新元素来包装文本(如果有非空格的字符)。如果找到一个子元素,那么这个方法就使用这个子元素,递归地调用它本身。对于 DOM 实现,我使用一对引用: child 和 next 来跟踪子元素排序列表中我所处的位置。在对当前子节点进行任何其它处理之前,先装入下个子节点的引用(第 7 行)。这样做使得我能够删除或替代当前的子节点,而不丢失我在列表中的踪迹。 当我创建一个新元素来包装非空白的文本内容(第 16-24 行)时,DOM 接口开始有点杂乱。用来创建元素的方法与文档关联并成为一个整体,所以我需要在所有者文档中检索当前我正在处理的元素(第 17 行)。我想将这个新元素放置在与现有的父元素相同的名称空间中,并且在 DOM 中,这意味着我需要构造元素的限定名称。根据是否有名称空间的前缀,这个操作会有所不同(第 18-19 行)。利用新元素的限定名称,以及现有元素中的名称空间 URI,我就能创建新元素(第 20-21 行)。一旦创建了新元素,我只要创建和添加文本节点来包装内容 String ,然后用新创建的元素来替代原始文本节点(第 22-24 行)。 清单 3. Crimson DOM 顶级代码 1 / parse the document from input stream 2 System.setProperty(javax.xml.parsers.DocumentBuilderFactory, 3 org.apache.crimson.jaxp.DocumentBuilderFactoryImpl); 4 DocumentBuilderFactory dbf = DocumentBuilderFactoryImpl.newInstance(); 5 dbf.setNamespaceAware(true); 6 DocumentBuilder builder = dbf.newDocumentBuilder(); 7 Document doc = builder.parse(in); 8 / recursively walk and modify document 9 modifyElement(doc.getDocumentElement();10 / write the document to output stream11 (XmlDocument)doc).write(out);清单 3 中的 Crimson DOM 示例代码使用了用于语法分析的 JAXP 接口。JAXP 为语法分析和转换 XML 文档提供了一个标准化的接口。本示例中的语法分析代码还可以用于 Xerces(对文档构建器类名称的特性设置有适当的更改)来替代较早给定的 Xerces 特定的示例代码。在本示例中,我首先在第 2 行到第 3 行中设置系统特性来选择要构造的 DOM 表示的构建器工厂类(JAXP 仅直接支持构建 DOM 表示,不支持构建本文中讨论的任何其它表示)。仅当想选择一个要由 JAXP 使用的特定 DOM 时,才需要这一步;否则,它使用缺省实现。出于完整性起见,我在代码中包含了设置这个特性,但是更普遍的是将它设置成一个 JVM 命令行参数。接着我在第 4 行到第 6 行中创建构建器工厂的实例,对使用那个工厂实例构造的构建器启用名称空间支持,并从构建器工厂创建文档构建器。最后(第 7 行),我使用文档构建器来对输入流进行语法分析并构造文档表示。为了写出文档,我使用 Crimson 中内部定义的基本方法。不保证在 Crimson 未来版本中支持这个方法,但是使用 JAXP 转换代码来将文档作为文本输出的替代方法需要诸如 Xalan 那样的 XSL 处理器的。那超出了本文的范围,但是要获取详细信息,可以查阅 Sun 中的 JAXP 教程。回页首JDOM使用 JDOM 的顶级代码比使用 DOM 实现的代码稍微简单一点。为构建文档表示(第 1-3 行),我使用带有由参数值禁止验证的 SAXBuilder 。通过使用提供的 XMLOutputter 类,将已修改的文档写入输出流同样简单(第 6-8 行)。 清单 4. JDOM 顶级代码 1 / parse the document from input stream 2 SAXBuilder builder = new SAXBuilder(false); 3 Document doc = builder.build(in); 4 / recursively walk and modify document 5 modifyElement(doc.getRootElement(); 6 / write the document to output stream 7 XMLOutputter outer = new XMLOutputter(); 8 outer.output(doc, out);清单 5 中 JDOM 的 modify 方法也比 DOM 的同一方法简单。我获取包含元素所有内容的列表并扫描了这张列表,检查文本(象 String 对象那样的内容)和元素。这张列表是“活的”,所以我能直接对它进行更改,而不必调用父元素上的方法。 清单 5. JDOM modify 方法 1 protected void modifyElement(Element element) 2 / loop through child nodes 3 List children = element.getContent(); 4 for (int i = 0; i children.size(); i+) 5 / handle child by node type 6 Object child = children.get(i); 7 if (child instanceof String) 8 / trim whitespace from content text 9 String trimmed = child.toString().trim();10 if (trimmed.length() = 0) 11 / delete child if only whitespace (adjusting index)12 children.remove(i-);13 else 14 / wrap the trimmed content with new element15 Element text = new Element(text, element.getNamespace();16 text.setText(trimmed);17 children.set(i, text);18 19 else if (child instanceof Element) 20 / handle child elements with recursive call21 modifyElement(Element)child);22 23 24 创建新元素的技术(第 14-17 行)非常简单,而且与 DOM 版本不同,它不需要访问父文档。回页首dom4jdom4j 的顶级代码比 JDOM 的稍微复杂些,但是它们的代码行非常类似。这里的主要区别是我保存了用来构建 dom4j 文档表示的 DocumentFactory (第 5 行),并在输出已修改的文档文本之后刷新了 writer(第 10 行)。 清单 6. dom4j 的顶级代码 1 / parse the document from input stream 2 SAXReader reader = new SAXReader(false); 3 Document doc = reader.read(in); 4 / recursively walk and modify document 5 m_factory = reader.getDocumentFactory(); 6 modifyElement(doc.getRootElement(); 7 / write the document to output stream 8 XMLWriter writer = new XMLWriter(out); 9 writer.write(doc);10 writer.flush();正如您在清单 6 中看到的,dom4j 使用一个工厂方法来构造文档表示(从语法分析构建)中包含的对象。根据接口来定义每个组件对象,所以实现其中一个接口的任何类型的对象都能包含在表示中(与 JDOM 相反,它使用具体类:这些类在某些情况中可以划分子类和被继承,但是在文档表示中使用的任何类都需要以原始 JDOM 类为基础)。通过使用不同工厂进行 dom4j 文档构建,您能获取不同系列的组件中构造的文档。在样本代码(第 5 行)中,我检索了用于构建文档的(缺省)文档工厂,并将它存储在一个实例变量( m_factory )中以供 modify 方法使用。并不严格需要这一步 可以在一个文档中同时使用来自不同工厂的组件,或者可以绕过工厂而直接创建组件的实例 但在该例中,我只
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年上海新上铁实业发展集团有限公司合肥分公司招聘1人考前自测高频考点模拟试题带答案详解
- 广州维修叉车安全培训课件
- 广州粤安安全培训课件
- 2025江西中医药大学附属医院编制外招聘45人(第二批)模拟试卷及答案详解(典优)
- 2025年福建省福清市市场监督管理局招聘20人模拟试卷附答案详解(完整版)
- 2025广东清远市连州市教育局招聘高中教师10人(编制)模拟试卷有答案详解
- 团队协作与沟通技巧培训材料模板
- 四年级数学(上)计算题专项练习及答案汇编
- 2025湖北交投集团部分中层管理岗位竞聘上岗20人模拟试卷附答案详解(典型题)
- 项目进度监控与质量控制记录表单
- 2025贵州省贵阳市殡仪服务中心公开招聘(编外)工作人员25人考试参考试题及答案解析
- 2025年国家安全知识竞赛试卷(答案+解析)
- 2025年贵州省凯里市辅警招聘考试题题库(含参考答案)
- 2025年四川基层法律服务工作者执业核准考试复习题及答案二
- 2025年全国企业员工全面质量管理知识竞赛题库(含答案)
- 2025年音乐学科会考练习卷及答案
- 大数据产业课件
- 潮汐能发电站课件
- 化妆详细教程课件
- 良好学习习惯养成课件
- 国际化跨国经营中的伦理问题概述
评论
0/150
提交评论