




已阅读5页,还剩28页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Part 1: Streaming API for XML (StAX) 是用 Java 语言处理 XML 的最新标准。作为一种面向流的方法,无论从性能还是可用性上都优于其他方法,如 DOM 和 SAX。本系列分为 3 部分,本文是第 1 部分,简要介绍了 StAX 及其处理 XML 的基于指针的 API。StAX 概述从一开始,Java API for XML Processing (JAXP) 就提供了两种方法来处理 XML:文档对象模型(DOM)方法是用标准的对象模型表示 XML 文档;Simple API for XML (SAX) 方法使用应用程序提供的事件处理程序来处理 XML。JSR-173 提出了一种面向流的新方法:Streaming API for XML (StAX)。其最终版本于 2004 年 3 月发布,并成为了 JAXP 1.4(将包含在即将发布的 Java 6 中)的一部分。如其名称所暗示的那样,StAX 把重点放在流上。实际上,StAX 与其他方法的区别就在于应用程序能够把 XML 作为一个事件流来处理。将 XML 作为一组事件来处理的想法并不新颖(事实上 SAX 已经提出来了),但不同之处在于 StAX 允许应用程序代码把这些事件逐个拉出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。StAX 实际上包括两套处理 XML 的 API,分别提供了不同程度的抽象。基于指针的 API 允许应用程序把 XML 作为一个标记(或事件)流来处理;应用程序可以检查解析器的状态,获得解析的上一个标记的信息,然后再处理下一个标记,依此类推。这是一种低层 API,尽管效率高,但是没有提供底层 XML 结构的抽象。较为高级的基于迭代器的 API 允许应用程序把 XML 作为一系列事件对象来处理,每个对象和应用程序交换 XML 结构的一部分。应用程序只需要确定解析事件的类型,将其转换成对应的具体类型,然后利用其方法获得属于该事件的信息。基本原理为了使用这两类 API,应用程序首先必须获得一个具体的 XMLInputFactory。根据传统的 JAXP 风格,要用到抽象工厂模式;XMLInputFactory 类提供了静态的 newInstance 方法,它负责定位和实例化具体的工厂。配置该实例可设置定制或者预先定义好的属性(其名称在类 XMLInputFactory 中定义)。最后,为了使用基于指针的 API,应用程序还要通过调用某个 createXMLStreamReader 方法获得一个 XMLStreamReader。如果要使用基于事件迭代器的 API,应用程序就要调用 createXMLEventReader 方法获得一个 XMLEventReader(如清单 1 所示)。清单 1. 获取和配置默认的 XMLInputFactory / get the default factory instanceXMLInputFactory factory = XMLInputFactory.newInstance();/ configure it to create readers that coalesce adjacent character sectionsfactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);XMLStreamReader r = factory.createXMLStreamReader(input);/ .XMLStreamReader 和 XMLEventReader 都允许应用程序迭代底层的 XML 流。两种方法的差别在于如何公开解析后的 XML InfoSet 信息片段。XMLStreamReader 就像一个指针,指在刚刚解析过的 XML 标记的后面,并提供了方法获得更多关于该标记的信息。这种方法节约内存,因为不用创建新的对象。但是,业务应用程序开发人员可能会发现 XMLEventReader 更直观一些,因为它实际上就是一个标准的 Java 迭代器,将 XML 变成了事件对象流。每个事件对象都封装了它所表示的特定 XML 结构固有的信息。本系列的第二部分将详细讨论这种基于事件迭代器的 API。使用哪种风格的 API 取决于具体情况。和基于指针的 API 相比,基于事件迭代器的 API 具有更多的面向对象特征。因此更便于应用于模块化的体系结构,因为当前的解析器状态反映在事件对象中,应用程序组件在处理事件的时候不需要访问解析器/读取器。此外,还可以使用 XMLInputFactory 的 createXMLEventReader(XMLStreamReader) 方法从 XMLStreamReader 创建 XMLEventReader。StAX 还定义了一种序列化器 API,Java 标准 XML 处理支持中一直缺少的一种特性。和解析一样,也包含两种风格的流式 API:处理标记的底层 XMLStreamWriter 和处理事件对象的高层 XMLEventWriter。XMLStreamWriter 提供了写入单个 XML 记号(比如开始和关闭标记或者元素属性)的方法,不检查这些标记是否格式良好。另一方面,XMLEventWriter 允许应用程序向输出中添加完整的 XML 事件。第 3 部分将详细讨论 StAX 序列化器 API。为什么使用 StAX?开始学习一种新的处理 XML 的 API 之前,可能要问是否值得这样做。事实上,StAX 所采用的基于拉的方法和其他方法相比有一些突出的优点。首先,不管使用哪种 API 风格,都是应用程序调用读取器(解析器)而不是相反。通过保留解析过程的控制权,可以简化调用代码来准确地处理它预期的内容。或者发生意外时停止解析。此外,由于该方法不基于处理程序回调,应用程序不需要像使用 SAX 那样模拟解析器的状态。StAX 仍然保留了 SAX 相对于 DOM 的优点。通过把重心从结果对象模型转移到解析流本身,从理论上说应用程序能够处理无限的 XML 流,因为事件固有的临时性,不会在内存中累积起来。对于那些使用 XML 作为消息传递协议而非表示文档内容的那些应用程序尤其重要,比如 Web 服务或即时消息应用程序。比方说,如果只是将其转换成特定于应用程序的对象模型然后就将其丢弃,那么为 Web 服务路由器 servlet 提供一个 DOM 就没有多少用处。使用 StAX 直接转化成应用程序模型效率更高。对于 Extensible Messaging and Presence Protocol(XMPP)客户机,根本不能使用 DOM,因为 XMPP 客户机/服务器流是随着用户输入的消息实时生成。等待流的关闭标签(以便最终建立 DOM)就意味着等待整个会话结束。通过把 XML 作为一系列的事件来处理,应用程序能够以最合适的方式响应每个事件(比如显示收到的即时消息等等)。由于其双向性,StAX 也支持链式处理,特别是在事件层上。接收事件(无论什么来源)的能力被封装在 XMLEventConsumer(XMLEventWriter 的扩展)接口中。因此,可以模块化地编写应用程序从 XMLEventReader(也是一个普通的迭代器,可以按迭代器处理)读取和处理 XML 事件、然后传递给事件消费者(如果需要可以进一步扩展处理链)。在第 2 部分将看到,也可使用应用程序提供的筛选器(实现了 EventFilter 接口的类)来定制 XMLEventReader 或者使用 EventReaderDelegate 修饰已有的 XMLEventReader。总而言之,和 DOM 以及 SAX 相比,StAX 使应用程序更贴近底层的 XML。使用 StAX,应用程序不仅可以建立需要的对象模型(而不需要处理标准 DOM),而且可以随时这样做,而不必等到解析器回调。下一节将深入讨论基于指针的 API 以及如何有效地使用它处理 XML 流。基于指针的 API如果使用基于指针的 API,应用程序通过在 XML 标记流中移动逻辑指针来处理 XML。基于指针的解析器实质上是一个状态机,在事件的驱动下从一个良好定义的状态转移到另一个状态。这里的触发事件是随着应用程序使用适当的方法推动解析器在标记流中前进而解析出来的 XML 标记。在每个状态,都可使用一组方法获得上一个事件的信息。一般来说,并非每个状态下都能使用所有的方法。使用基于指针的方法,应用程序首先必须通过调用其 createXMLStreamReader 方法从 XMLInputFactory 得到 XMLStreamReader。该方法有多个版本,支持不同类型的输入。比方说,可以创建 XMLStreamReader 解析 plain java.io.InputStream、java.io.Reader 或者 JAXP Source(javax.xml.transform.Source)。从理论上说,后一种办法很容易和其他 JAXP 技术交互,比如 SAX 和 DOM。清单 2. 创建 XMLStreamReader 解析 InputStream URL url = new URL(uri);InputStream input = url.openStream();XMLInputFactory factory = XMLInputFactory.newInstance();XMLStreamReader r = factory.createXMLStreamReader(uri, input);/ process the stream/ .r.close();input.close();XMLStreamReader 接口基本上定义了基于指针的 API(虽然标记常量在其超类型 XMLStreamConstants 接口中定义)。之所以称为基于指针,是因为读取器就像是底层标记流上的指针。应用程序可以沿着标记流向前推进指针并分析当前指针所在位置的标记。XMLStreamReader 提供了多种方法导航标记流。为了确定当前指针所指向的标记(或事件)的类型,应用程序可以调用 getEventType()。该方法返回接口 XMLStreamConstants 中定义的一个标记常量。移动到下一个标记,应用程序可以调用 next()。该方法也返回解析的标记的类型,如果接着调用 getEventType() 则返回的值相同。只有当方法 hasNext() 返回 true 时(就是说还有其他标记需要解析)才能调用该方法(以及其他移动读取器的方法)。清单 3. 使用 XMLStreamReader 处理 XML 的常用模式/ create an XMLStreamReaderXMLStreamReader r = .;try int event = r.getEventType(); while (true) switch (event) case XMLStreamConstants.START_DOCUMENT: / add cases for each event of interest / . if (!r.hasNext() break; event = r.next(); finally r.close();还与其他几种方法可以移动 reader。 nextTag() 方法将跳过所有的空白、注释或处理指令,直到遇到 START_ELEMENT 或 END_ELEMENT。该方法在解析只含元素的内容时很有用,如果在发现标记之前遇到非空白文本(不包括注释或处理指令),就会抛出异常。getElementText() 方法返回元素的开始和关闭标签(即 START_ELEMENT 和 END_ELEMENT)之间的所有文本内容。如果遇到嵌套的元素就会抛出异常。请注意,这里的 “标记” 和 “事件” 可以互换使用。虽然基于指针的 API 的文档说的是事件,但把输入源看成标记流很方便。而且不容易造成混乱,因为还有一整套基于事件的 API(那里的事件是真正的对象)。不过,XMLStreamReader 的事件本质上并非都是标记。比方说,START_DOCUMENT 和 END_DOCUMENT 事件不需要对应的标记。前一个事件是解析开始之前发生,后者则在没有更多解析工作要做的时候发生(比如解析完成最后一个元素的关闭标签之后,读取器处于 END_ELEMENT 状态,但是如果没有发现更多的标记需要解析,读取器就会切换到 END_DOCUMENT 状态)。处理 XML 文档在每个解析器状态,应用程序都可通过可用的方法获得相关信息。比如,无论当前是什么类型的事件,getNamespaceContext() 和 getNamespaceURI() 方法可以获得当前有效的名称空间上下文和名称空间 URI。类似的,getLocation() 可以获得当前事件的位置信息。方法 hasName() 和 hasText() 可以分别判断当前事件是否有名称(比如元素或属性)或文本(比如字符、注释或 CDATA)。方法 isStartElement()、isEndElement()、isCharacters() 和 isWhiteSpace() 可以方便地确定当前事件的性质。最后,方法 require(int, String, String) 可以声明预期的解析器状态;除非当前事件是指定的类型,并且本地名和名称空间(如果给出的话)与当前事件匹配,否则该方法将抛出异常。清单 4. 如果当前事件是 START_ELEMENT 使用有关的属性方法if (reader.getEventType() = XMLStreamConstants.START_ELEMENT) System.out.println(Start Element: + reader.getName(); for(int i = 0, n = reader.getAttributeCount(); i n; +i) QName name = reader.getAttributeName(i); String value = reader.getAttributeValue(i); System.out.println(Attribute: + name + = + value); 创建之后,XMLStreamReader 将从 START_DOCUMENT 状态开始(即 getEventType() 返回 START_DOCUMENT)。处理标记的时候应考虑到这一点。和迭代器不同,不需要先移动指针(使用 next())来进入合法的状态。同样地,当读取器转换到最终状态 END_DOCUMENT 之后,应用程序也不应再移动它。在这种状态下,hasNext() 方法将返回 false。START_DOCUMENT 事件提供了获取关于文档本身信息的方法,如 getEncoding()、getVersion() 和 isStandalone()。应用程序也可调用 getProperty(String) 获得命名属性的值,不过一些属性仅在特定状态做了定义(比方说,如果当前事件是 DTD,则属性 javax.xml.stream.notations 和 javax.xml.stream.entities 分别返回所有的符号和实体声明)。在 START_ELEMENT 和 END_ELEMENT 事件中,可以使用和元素名称以及名称空间有关的方法(如 getName()、getLocalName()、getPrefix() 和 getNamespaceXXX()),在 START_ELEMENT 事件中还可使用与属性有关的方法(getAttributeXXX())。ATTRIBUTE 和 NAMESPACE 也被识别为独立的事件,虽然在解析 典型的 XML 文档时不会用到。但是当 ATTRIBUTE 或 NAMESPACE 节点作为 XPath 查询结果返回时可以使用。和基于文本的事件(如 CHARACTERS、CDATA、COMMENT 和 SPACE),可使用各种 getTextXXX() 方法取得文本。可以分别使用 getPITarget() 和 getPIData() 检索 PROCESSING_INSTRUCTION 的目标和数据。ENTITY_REFERENCE 和 DTD 也支持 getText(),ENTITY_REFERENCE 还支持 getLocalName()。解析完成后,应用程序关闭读取器并释放解析过程中获得的资源。请注意这样并没有关闭底层的输入源。清单 5 提供了一个完整的例子,使用基于指针的 API 处理 XML 文档。首先取得 XMLInputFactory 的默认实例并创建一个 XMLStreamReader 解析给定的输入流。然后不断检查读取器的状态,根据当前事件的类型报告某些信息(比如在 START_ELEMENT 状态下报告元素名及元素属性)。最后,遇到 END_DOCUMENT 时关闭读取器。清单 5. 使用 XMLStreamReader 解析 XML 文档的完整例子XMLInputFactory factory = XMLInputFactory.newInstance();XMLStreamReader r = factory.createXMLStreamReader(input);try int event = r.getEventType(); while (true) switch (event) case XMLStreamConstants.START_DOCUMENT: out.println(Start Document.); break; case XMLStreamConstants.START_ELEMENT: out.println(Start Element: + r.getName(); for(int i = 0, n = r.getAttributeCount(); i n; +i) out.println(Attribute: + r.getAttributeName(i) + = + r.getAttributeValue(i); break; case XMLStreamConstants.CHARACTERS: if (r.isWhiteSpace() break; out.println(Text: + r.getText(); break; case XMLStreamConstants.END_ELEMENT: out.println(End Element: + r.getName(); break; case XMLStreamConstants.END_DOCUMENT: out.println(End Document.); break; if (!r.hasNext() break; event = r.next(); finally r.close();XMLStreamReader 的高级用法通过调用 XMLInputFactory 的带有基本读取器的 createFilteredReader 方法和一个应用程序定义的筛选器(即实现 StreamFilter 的类实例),可以创建筛选过的 XMLStreamReader。导航筛选过的读取器时,读取器每次移动到下一个标记之前都会询问筛选器。如果筛选器认可了当前事件,就将其公开给筛选过的读取器。否则跳过这个标记并检查下一个,依此类推。这种方法可以让开发人员创建一个仅处理解析内容子集的基于指针的 XML 处理程序,并与针对不同的扩展的内容模型的筛选器结合使用。执行更复杂的流操作,可以创建 StreamReaderDelegate 的子类并重写合适的方法。然后使用这个子类的实例包装基本 XMLStreamReader,从而为应用程序提供一个修改过的基本 XML 流的视图。可通过这种技术对 XML 流执行简单的转换,比如筛掉或者替换特定的标记,甚至增加新的标记。清单 6 用定制的 StreamReaderDelegate 包装了基本 XMLStreamReader,重写了 next() 方法来跳过 COMMENT 和 PROCESSING_INSTRUCTION 事件。使用该读取器时,应用程序不用担心会遇到这种类型的标记。清单 6. 使用定制的 StreamReaderDelegate 筛选注释和处理指令 URL url = new URL(uri);InputStream input = url.openStream();XMLInputFactory f = XMLInputFactory.newInstance();XMLStreamReader r = f.createXMLStreamReader(uri, input);XMLStreamReader fr = new StreamReaderDelegate(r) public int next() throws XMLStreamException while (true) int event = super.next(); switch (event) case XMLStreamConstants.COMMENT: case XMLStreamConstants.PROCESSING_INSTRUCTION: continue; default: return event; ;try int event = fr.getEventType(); while (true) switch (event) case XMLStreamConstants.COMMENT: case XMLStreamConstants.PROCESSING_INSTRUCTION: / this should never happen throw new IllegalStateException(Filter failed!); default: / process XML normally if (!fr.hasNext() break; event = fr.next(); finally fr.close();input.close();基于指针处理之外的其他技术可以看到,基于指针的 API 主要是为了提高效率。所有的状态信息可以直接从流读取器获得,不需要创建额外的对象。非常适用于性能和低内存占用至关重要的应用程序。人们早就认识到了拉式 XML 解析的好处。事实上,StAX 本身源于一种称为 XML Pull Parsing 的方法。XML Pull Parser API 类似于 StAX 所提供的基于指针的 API,可以通过分析解析器的状态获得上一个解析事件的信息,然后移动到下一个,依此类推。但没有提供基于事件迭代器的 API。这是一种非常轻型的方法,特别适合资源受限的环境,比如 J2ME。但是,很少有实现提供企业级特性如验证,因此 XML Pull 一直未受到企业 Java 开发人员的关注。基于以往拉式解析器实现的经验,StAX 的创建者选择了在基于指针的 API 之外增加一种面向对象的 API。虽然 XMLEventReader 接口看起来似乎很简单,但是基于事件迭代器的方法具有一个基于指针的方法不具备的重要优点。通过将解析器事件变成一级对象,从而让应用程序可以采用面向对象的方式处理它们。这样做有助于模块化和不同应用程序组件之间的代码重用。清单 7. 使用 StAX XMLEventReader 解析 XML XMLInputFactory inputFactory = XMLInputFactory.newInstance();XMLEventReader reader = inputFactory.createXMLEventReader(input);try while (reader.hasNext() XMLEvent e = reader.nextEvent(); if (e.isCharacters() & (Characters) e).isWhiteSpace() continue; out.println(e); finally reader.close();结束语本文介绍了 StAX 及其基于指针的 API。第 2 部分将深入讨论事件迭代器 API。Part 2:Streaming API for XML (StAX) 的基于事件迭代器 API 无论在性能还是在可用性上都有其他 XML 处理方法所不及的独到之处。第 1 部分介绍了 StAX 并详细讨论了它的基于指针的 API。本文进一步讨论基于事件迭代器 API 及其为 Java 开发人员带来的好处。使用 StAX 解析 XML第 1 部分(请参阅 参考资料)提到,StAX 提供了两种风格的处理 XML 的 API。基于指针的 API 是解析 XML 的低层方法。使用这种方法,应用程序沿着 XML 标记流移动指针,在每一步中检查解析器的状态来了解解析内容的更多信息。这种方法效率很高,特别适用于资源受限的环境。但是,基于指针的 API 不是面向对象的,因而不适合 Java 应用程序,尤其是在代码的可扩展性和可维护性与性能同样重要的企业领域中就更是如此。比方说,多层 Web 服务使用一般组件处理消息信封,而把特定于消息的内容处理(如参数绑定)委托给其他组件完成,这种情况下就能从面向对象的方法中获益。StAX 提供的另一种风格的 API 以事件对象为中心。和基于指针的 API 一样,这也是一种基于拉的 XML 解析方法:应用程序使用提供的方法从解析器中拉出每个事件,按照需要处理该事件,依此类推,直到流解析完成(或者应用程序决定停止解析)。XMLEventReader 接口简介事件迭代器 API 的主要接口是 XMLEventReader。和 XMLStreamReader 相比它的方法要少很多。这是因为 XMLEventReader 用于迭代事件对象流(事实上 XMLEventReader 扩展了 java.util.Iterator)。关于解析事件的所有信息都封装在事件对象而不是读取器中。要使用基于事件迭代器的 API,应用程序首先必须从 XMLInputFactory 获得 XMLEventReader 的实例。工厂本身可用标准 JAXP 方法获得,它依靠抽象工厂模式支持可插入的服务提供者。这就使得获取默认的 XMLInputFactory 实现的实例和调用 XMLInputFactory.getInstance() 一样简单,如清单 1 所示。清单 1. 使用默认的 XMLInputFactory 实现创建 XMLEventReader String uri = /atom.xml;URL url = new URL(uri);InputStream input = url.openStream();XMLInputFactory factory = XMLInputFactory.newInstance();XMLEventReader reader = factory.createXMLEventReader(uri, input);.XMLInputFactory 支持各种可用于创建 XMLEventReader 的输入源。除了 Java I/O 包中的 InputStream 和 Reader 之外,还支持 JAXP Source(来自 TrAX),后者有助于集成 StAX 和 JAXP 的转换 API(TrAX)。最后,还可以从 XMLStreamReader 创建 XMLEventReader。这种用法可以很好地说明基于事件迭代器的 API 如何堆叠于基于指针的 API 之上。事实上,实现通常要使用其他输入源创建一个 XMLStreamReader,然后再用它创建 XMLEventReader。使用 XMLEventReader 创建 XMLEventReader 之后,应用程序可用它迭代表示底层 XML 流的 InfoSet 片段的事件。由于接口 XMLEventReader 扩展了 java.util.Iterator,可以使用标准迭代器方法如 hasNext() 和 next()。但是请注意,不支持 remove() 方法,如果调用该方法会抛出异常。XMLEventReader 还提供了一些方便的方法来简化 XML 处理: nextEvent() 本质上是一种等同于 Iterator 的 next() 方法的强类型方法,它返回一个 XMLEvent,它是所有事件对象的基本接口。 nextTag() 能够跳过所有无关紧要的空白直到下一个开始或结束标记。因此返回值将是 StartElement 或 EndElement 事件(参见后述)。该方法在处理纯元素(即文档类型声明 DTD 中声明为 EMPTY 的元素)内容时尤其有用。 getElementText() 可以访问纯文本元素的文本内容(开始标签到结束标签之间)。从 StartElement 作为下一个预期事件开始,该方法在遇到 EndElement 之前将所有字符连接起来并返回结果字符串。 peek() 可以得到迭代器将返回的下一个事件(如果有)但是不移动迭代器。 清单 2 示范了 XMLEventReader 方法如何用于迭代 Atom 提要。Atom 是用于 Web 发布的一种连锁格式。该例首先获得 XMLInputFactory 的默认实例然后用它创建 XMLEventReader 来解析给定 URL 的 Atom 提要。迭代事件的过程中,peek() 方法判定下一个事件是否从 icon 元素开始,该元素包含提要的图标 URL。如果是,则用 getElementText() 方法获取元素的文本内容(即图标 URL),然后停止迭代。清单 2. 使用 peek() 和 getElementText() 提取 Atom 提要的图标 URLfinal QName ICON = new QName(/2005/Atom, icon);URL url = new URL(uri);InputStream input = url.openStream();XMLInputFactory factory = XMLInputFactory.newInstance();XMLEventReader reader = factory.createXMLEventReader(uri, input);try while (reader.hasNext() XMLEvent event = reader.peek(); if (event.isStartElement() StartElement start = event.asStartElement(); if (ICON.equals(start.getName() System.out.println(reader.getElementText(); break; reader.nextEvent(); finally reader.close();input.close();返回的事件对象是不变的,应用程序可以保存到解析过程之后。但是应用程序也可定义不同的事件保留(或重用)策略,请参阅第 3 部分。应用程序也可用 getProperty(String) 从底层实现中获得一个定制的或预先定义的属性值。完成之后,应用程序应该调用读取器的 close() 方法关闭它,以便释放处理所占用的资源。使用 XMLEventReader 迭代事件流非常简单。处理这些事件需要知道和熟悉 StAX XMLEvent 的层次结构,下面我们来讨论它。事件以及如何在 XML 解析器中使用事件前面已经强调过,XMLEventReader 在解析过程的每一步之后通过事件对象和应用程序通信自己的状态。整个 API 中使用的事件对象的标准类型定义在 javax.xml.stream.events 包中。接口 XMLEvent 表示类型层次结构的根,所有类型的事件必须扩展该接口。表示各种指针层事件类型(在基于指针的 API 中)定义在接口 XMLStreamConstants 中。不过,在第 3 部分将看到也可使用定制的接口(只要扩展了 XMLEvent)。导航 XMLEvent 层次结构从解析器中检索到事件之后,应用程序通常需要将其向下转换成 XMLEvent 的子类型以便访问该特定类型的信息。有多种方法,除了蛮力的 instanceof 检查(即通过一系列的 if/then 语句检查返回的事件是否实现了指定接口)以外,XMLEvent 还提供了 getEventType() 方法返回 XMLStreamConstants 中定义的事件常量。可基于该信息对事件进行向下类型转换。比方说,如果事件的 getEventType() 返回 START_ELEMENT,它就可以安全地转换成 StartElement。确定事件具体类型的另一种方法是使用为此提供的布尔查询方法。比如,如果事件是一个 Attribute 则 isAttribute() 返回 true,如果是 StartElement 则 isStartElement() 返回 true,等等。此外还有几种方便的方法可用于向下类型转换。asStartElement()、asEndElement() 和 asCharacters() 分别将相应的事件转换成 StartElement、EndElement 和 Characters。清单 3 中首先使用 isStartElement() 和 asStartElement() 方法确定检索的事件是否是 StartElement,然后将其向下转换成 StartElement 类型,从而访问元素名。清单 3. 确定事件类型并向下转换成对应的接口 / get an event from the reader.if (event.isStartElement() StartElement start = event.asStartElement(); / use methods provided by StartElement.除了和类型层次结构有关的方法外,XMLEventType 还提供了 getLocation()、getSchemaType() 和 writeAsEncodedUnicode(Writer) 方法。getLocation() 返回的 Location 对象提供了关于事件在底层输入源中的位置(比如该事件结束的行列号)的可选信息。getSchemaType() 用于检索和给定事件有关的 XML Schema 信息(如果实现支持该功能)。writeAsEncodedUnicode(Writer) 方法以标准的方式定义了将事件对象写入 java.io.Writer 的契约。这些方法对于定义定制的事件(将在下一期讨论)特别有用,因为可以让序列化器委托 XMLEvent 派生类的序列化而不需要应用程序使用定制的序列化器。处理 XML 文档解析表示完整 XML 文档的流时,XMLEventReader 返回的第一个事件是 StartDocument。该接口提供了获得文档本身信息的方法。比如,getSystemId() 方法可以返回文档的系统 ID(如果知道的话)。getVersion() 返回该文档使用的 XML 版本。默认的版本是 1.0,除非在文档的 XML 声明中指定了其他值。getCharacterEncodingScheme() 返回文档的字符编码,不论在 XML 声明中显式指定还是解析器自动检测。默认值为 UTF-8,除非给出了外部标记声明或者在文档 XML 声明中显式指定了该值,否则 isStandalone() 返回 true。访问 DTD如果 XMLEventReader 遇到 DTD 则返回 DTD 事件。如果应用程序不关心 DTD,可以通过将解析器的 javax.xml.stream.supportDTD 属性设置为 false 来关闭该特性。事件的 getDocumentTypeDeclaration() 方法可以将整个 DTD 作为一个字符串检索,包括内部子集。这个实现实际上可将 DTD 处理成更加结构化的形式(特定于提供的)并通过调用 getProcessedDTD() 方法使其可用。getEntities() 方法返回 EntityDeclaration 事件列表(参见后述),这些事件表示一般外部实体声明,包括内部和外部实体。此外,getNotations() 方法返回 NotationDeclaration 事件列表(同样将在后面说明),用于表示声明的符号。EntityDeclaration 事件表示在文档的 DTD 中声明的非解析的一般实体。该事件不被单独报告,而是作为 DTD 事件的一部分。它提供了用于获取实体的名称、公共和系统 ID 以及相关的符号名的方法(分别使用 getName()、getPublicId()、getSystemId() 和 getNotationName())。如果是内部实体,getReplacementText() 方法可检索其替换文本。类似的,NotationDeclaration 事件也只能通过 DTD 事件访问。它表示符号声明。除了名称以外(getName() 方法),该接口还提供了检索符号的公共和系统 ID 的方法(分别是 getPublicId() 和 getSystemId())。两者至少要有一个可用。清单 4 示范了如何处理非解析外部实体引用。该例中,虚构的 catalog 文档包含了对内容放在 PDF 或 HTML 文件(两者都不是有效的 XML)的出版物的引用。迭代这些事件的过程中,从 DTD 事件中提取符号声明并按照名字缓存。遇到实体引用时,取得实体声明并根据名称检索缓存的符号声明。实际的应用程序可能会使用符号标识符来定位适当的内容处理程序并使用实体的系统标识符作为其输入。清单 4. 获取非解析实体和符号信息的例子 final String xml = + !DOCTYPE catalog + + + + + + + + + + &overview; + &chapter1; + ;Map notations = new HashMap();StringReader input = new StringReader(xml);XMLInputFactory f = XMLInputFactory.newInstance();XMLEventReader r = f.createXMLEventReader(/catalog.xml, input);PrintWriter out = new PrintWriter(System.out);try while (r.hasNext() XMLEvent event = r.nextEvent(); switch (event.getEventType() case XMLStreamConstants.ENTITY_REFERENCE: EntityReference ref = (EntityReference) event; EntityDeclaration decl = ref.getDeclaration(); NotationDeclaration n = (NotationDeclaration) notations.get(decl.getNotationN
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030都市青年租赁住房需求演变与商业机会评估报告
- 2025-2030辅助生殖技术服务标准化与市场规范发展报告
- 2025-2030费托蜡行业绿色工厂评价指标体系构建
- 2025-2030费托蜡新兴应用领域市场机遇分析
- 2025-2030费托蜡在声学材料中的阻尼性能优化与噪声控制应用
- 2025-2030费托蜡副产品高值化利用技术突破与经济效益测算
- 市政工程项目质量安全管理手册
- 2025年产品采购与销售合同标准范本
- 人力资源职业规划与发展报告
- 2025解除合作合同协议范本
- 2025年省盐业投资控股集团有限公司招聘笔试备考试题带答案详解
- 钢管桩施工土建方案范例
- 保安三级安全考试题库及答案解析
- 市场仿真花施工方案
- 2025年入团知识考试题库(含答案)
- 《人工智能导论》(第2版)高职全套教学课件
- 疑问句(课件)六年下册英语人教PEP版
- 视力残疾康复服务规范
- HG T 3690-2022 工业用钢骨架聚乙烯塑料复合管
- 医院医保科绩效考核标准
- 机电设备调试协议书
评论
0/150
提交评论