这些Java教程是针对JDK 8编写的。本页面描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及后续版本中更新的语言特性的摘要,请参阅Java语言变更。
有关所有JDK版本的新功能、增强功能和已删除或不推荐使用的选项的信息,请参阅JDK发行说明。
一般来说,StAX程序员使用XMLInputFactory、XMLOutputFactory和XMLEventFactory类来创建XML流读取器、写入器和事件。通过在工厂上设置属性来进行配置,可以将实现特定的设置传递给底层实现,使用工厂上的setProperty方法。类似地,可以使用getProperty工厂方法查询实现特定的设置。
下面描述了XMLInputFactory、XMLOutputFactory和XMLEventFactory类,然后讨论资源分配、命名空间和属性管理、错误处理,最后使用游标和迭代器API读取和写入流。
StAX工厂类XMLInputFactory、XMLOutputFactory和XMLEventFactory允许您定义和配置XML流读取器、写入器和事件的实现实例。
XMLInputFactory类允许您配置工厂创建的XML流读取器处理器的实现实例。通过调用newInstance方法来创建XMLInputFactory抽象类的新实例。然后使用静态方法XMLInputFactory.newInstance创建一个新的工厂实例。
继承自JAXP,XMLInputFactory.newInstance方法通过以下查找过程确定要加载的特定XMLInputFactory实现类:
使用javax.xml.stream.XMLInputFactory系统属性。
使用Java SE平台的Java运行时环境(JRE)目录中的lib/xml.stream.properties文件。
如果可用,使用Services API通过查找JRE可用的JAR文件中的META-INF/services/javax.xml.stream.XMLInputFactory文件确定类名。
使用平台默认的XMLInputFactory实例。
在获取到适当的XMLInputFactory引用之后,应用程序可以使用工厂来配置和创建流实例。下表列出了XMLInputFactory支持的属性。有关更详细的列表,请参阅StAX规范。
属性 |
描述 |
---|---|
isValidating |
打开实现特定的验证。 |
isCoalescing |
(必需) 要求处理器合并相邻的字符数据。 |
isNamespaceAware |
关闭命名空间支持。所有实现都必须支持命名空间。对非命名空间感知文档的支持是可选的。 |
isReplacingEntityReferences |
(必需) 要求处理器将内部实体引用替换为它们的替换值,并将它们报告为字符或描述实体的一组事件。 |
isSupportingExternalEntities |
(必需) 要求处理器解析外部解析实体。 |
reporter |
(必需) 设置和获取 XMLReporter 接口的实现。 |
resolver |
(必需) 设置和获取 XMLResolver 接口的实现。 |
allocator |
(必需) 设置和获取 XMLEventAllocator 接口的实现。 |
通过调用类的 newInstance 方法来创建抽象类 XMLOutputFactory 的新实例。然后使用静态方法 XMLOutputFactory.newInstance 创建一个新的工厂实例。获取实例的算法与 XMLInputFactory 相同,但是引用了 javax.xml.stream.XMLOutputFactory 系统属性。
XMLOutputFactory仅支持一个属性,javax.xml.stream.isRepairingNamespaces。此属性是必需的,其目的是创建默认前缀并将其与命名空间URI关联起来。有关更多信息,请参见StAX规范。
通过调用类的newInstance方法来创建抽象类XMLEventFactory的新实例。然后使用静态方法XMLEventFactory.newInstance来创建新的工厂实例。此工厂引用javax.xml.stream.XMLEventFactory属性来实例化工厂。获取实例的算法与XMLInputFactory和XMLOutputFactory相同,但引用了javax.xml.stream.XMLEventFactory系统属性。
XMLEventFactory没有默认属性。
StAX规范处理资源解析,属性和命名空间以及错误和异常,如下所述。
XMLResolver接口提供了在XML处理期间解析资源的方法。应用程序在XMLInputFactory上设置接口,然后该工厂实例在创建的所有处理器上设置接口。
StAX处理器使用游标接口中的查找方法和字符串以及迭代器接口中的Attribute和Namespace事件来报告属性。请注意,命名空间被视为属性,尽管在游标和迭代器API中,命名空间与属性分别报告。还要注意,对于StAX处理器来说,命名空间处理是可选的。有关命名空间绑定和可选命名空间处理的完整信息,请参见StAX规范。
所有致命错误都通过javax.xml.stream.XMLStreamException接口报告。所有非致命错误和警告都使用javax.xml.stream.XMLReporter接口报告。
正如本课程前面所述,使用StAX处理器读取XML流以及您得到的返回值,根据使用StAX游标API还是事件迭代器API而有很大的不同。以下两个部分描述了如何使用这些API之一读取XML流。
在StAX游标API中,XMLStreamReader接口允许您只能以前向方式读取XML流或文档,每次只读取一个信息项。以下方法可用于从流中提取数据或跳过不需要的事件:
获取属性的值
读取XML内容
确定元素是否具有内容或为空
对属性集合进行索引访问
对命名空间集合进行索引访问
获取当前事件的名称(如果适用)
获取当前事件的内容(如果适用)
XMLStreamReader的实例在任何时候只有一个当前事件,其方法操作该事件。当您在流上创建XMLStreamReader实例时,初始当前事件是START_DOCUMENT状态。然后,可以使用XMLStreamReader.next方法前进到流中的下一个事件。
XMLStreamReader.next方法加载流中下一个事件的属性。然后,您可以通过调用XMLStreamReader.getLocalName和XMLStreamReader.getText方法访问这些属性。
当XMLStreamReader游标位于StartElement事件上时,它会读取事件的名称和任何属性,包括命名空间。可以使用索引值访问事件的所有属性,也可以通过命名空间URI和本地名称查找属性。但请注意,只有当前StartEvent上声明的命名空间可用;先前声明的命名空间不会被保留,重新声明的命名空间也不会被删除。
XMLStreamReader提供以下方法来检索有关命名空间和属性的信息:
int getAttributeCount(); String getAttributeNamespace(int index); String getAttributeLocalName(int index); String getAttributePrefix(int index); String getAttributeType(int index); String getAttributeValue(int index); String getAttributeValue(String namespaceUri, String localName); boolean isAttributeSpecified(int index);
还可以使用另外三个方法访问命名空间:
int getNamespaceCount(); String getNamespacePrefix(int index); String getNamespaceURI(int index);
此示例取自StAX规范,演示了如何实例化输入工厂、创建读取器并迭代XML流的元素:
XMLInputFactory f = XMLInputFactory.newInstance(); XMLStreamReader r = f.createXMLStreamReader( ... ); while(r.hasNext()) { r.next(); }
StAX事件迭代器API中的XMLEventReader API提供了将XML流中的事件映射到分配的事件对象的方法,这些对象可以自由重用,并且API本身可以扩展以处理自定义事件。
XMLEventReader提供了四种迭代解析XML流的方法:
next:返回流中的下一个事件
nextEvent:返回下一个类型化的XMLEvent
hasNext:如果流中还有更多事件要处理,则返回true
peek:返回事件,但不迭代到下一个事件
例如,以下代码片段演示了XMLEventReader方法的声明:
package javax.xml.stream; import java.util.Iterator; public interface XMLEventReader extends Iterator { public Object next(); public XMLEvent nextEvent() throws XMLStreamException; public boolean hasNext(); public XMLEvent peek() throws XMLStreamException; // ... }
要读取流中的所有事件并将它们打印出来,可以使用以下代码:
while(stream.hasNext()) { XMLEvent event = stream.nextEvent(); System.out.print(event); }
您可以通过其关联的javax.xml.stream.StartElement访问属性,如下所示:
public interface StartElement extends XMLEvent { public Attribute getAttributeByName(QName name); public Iterator getAttributes(); }
您可以使用StartElement接口上的getAttributes方法,在该StartElement上使用Iterator来遍历所有声明的属性。
类似于读取属性,可以通过调用StartElement接口上的getNamespaces方法来使用Iterator读取命名空间。只返回当前StartElement的命名空间,并且应用程序可以使用StartElement.getNamespaceContext获取当前的命名空间上下文。
StAX是一个双向API,光标和事件迭代器API都有自己的接口集来编写XML流。与用于读取流的接口一样,光标和事件迭代器的编写器API之间存在重要的差异。以下各节将介绍如何使用这些API编写XML流。
StAX游标API中的XMLStreamWriter接口允许应用程序向XML流写入数据,或创建全新的流。XMLStreamWriter具有以下方法:
写入格式良好的XML
刷新或关闭输出
写入限定名称
请注意,XMLStreamWriter的实现不需要对输入执行格式良好性或有效性检查。某些实现可能会执行严格的错误检查,而其他实现可能不会。您实现的规则适用于XMLOutputFactory类中定义的属性。
writeCharacters方法用于转义字符,如&、<、>和"。绑定前缀可以通过传递前缀的实际值、使用setPrefix方法或设置默认命名空间声明的属性来处理。
以下示例摘自StAX规范,展示了如何实例化一个输出工厂、创建一个写入器并写入XML输出:
XMLOutputFactory output = XMLOutputFactory.newInstance(); XMLStreamWriter writer = output.createXMLStreamWriter( ... ); writer.writeStartDocument(); writer.setPrefix("c","http://c"); writer.setDefaultNamespace("http://c"); writer.writeStartElement("http://c","a"); writer.writeAttribute("b","blah"); writer.writeNamespace("c","http://c"); writer.writeDefaultNamespace("http://c"); writer.setPrefix("d","http://c"); writer.writeEmptyElement("http://c","d"); writer.writeAttribute("http://c", "chris","fry"); writer.writeNamespace("d","http://c"); writer.writeCharacters("Jean Arp"); writer.writeEndElement(); writer.flush();
该代码生成以下XML(换行不是规范的):
<?xml version=’1.0’ encoding=’utf-8’?> <a b="blah" xmlns:c="http://c" xmlns="http://c"> <d:d d:chris="fry" xmlns:d="http://c"/>Jean Arp</a>
StAX事件迭代器API中的XMLEventWriter接口允许应用程序向XML流写入数据,或创建全新的流。该API可以扩展,但主要API如下:
public interface XMLEventWriter { public void flush() throws XMLStreamException; public void close() throws XMLStreamException; public void add(XMLEvent e) throws XMLStreamException; // ... other methods not shown. }
XMLEventWriter的实例由XMLOutputFactory的实例创建。流事件会被迭代地添加,一旦添加到事件写入器实例后,事件就无法修改。
StAX实现要求将最后一个StartElement缓冲,直到在流中添加或遇到除Attribute或Namespace之外的事件。这意味着当您向流中添加Attribute或Namespace时,它将附加到当前的StartElement事件。
您可以使用Characters方法转义字符,例如&、<、>和"。
可以使用setPrefix(...)方法显式绑定输出时使用的前缀,可以使用getPrefix(...)方法获取当前前缀。请注意,默认情况下,XMLEventWriter将命名空间绑定添加到其内部命名空间映射中。前缀在绑定它们的事件的相应EndElement之后失效。