使用 StAX

原文: https://docs.oracle.com/javase/tutorial/jaxp/stax/using.html

通常,StAX 程序员使用XMLInputFactoryXMLOutputFactoryXMLEventFactory类创建 XML 流读取器,编写器和事件。通过在工厂上设置属性来完成配置,从而可以使用工厂上的setProperty方法将特定于实现的设置传递给底层实现。同样,可以使用getProperty工厂方法查询特定于实现的设置。

下面介绍XMLInputFactoryXMLOutputFactoryXMLEventFactory类,然后讨论资源分配,命名空间和属性管理,错误处理,最后阅读和使用游标和迭代器 API 编写流。

StAX 工厂类

StAX 工厂类。 XMLInputFactoryXMLOutputFactoryXMLEventFactory ,让您定义和配置 XML 流阅读器,流编写器和事件类的实现实例。

的 XMLInputFactory

XMLInputFactory类允许您配置工厂创建的 XML 流读取器处理器的实现实例。抽象类XMLInputFactory的新实例是通过调用类上的newInstance方法创建的。然后使用静态方法XMLInputFactory.newInstance创建新的工厂实例。

从[JGP]派生, XMLInputFactory.newInstance方法通过使用以下查找过程确定要加载的特定XMLInputFactory实现类:

  1. 使用javax.xml.stream.XMLInputFactory系统属性。

  2. 使用 Java SE 平台的 Java 运行时环境(JRE)目录中的lib / xml.stream.properties文件。

  3. 使用 Services API(如果可用)通过查看 JRE 可用的 JAR 文件中的META-INF / services / javax.xml.stream.XMLInputFactory文件来确定类名。

  4. 使用平台默认XMLInputFactory实例。

在获得对适当的XMLInputFactory的引用之后,应用程序可以使用工厂来配置和创建流实例。下表列出了XMLInputFactory支持的属性。有关更详细的列表,请参阅 StAX 规范。

javax.xml.stream.XMLInputFactory Properties

属性 描述
isValidating 打开特定于实现的验证。
是合并 (必需)要求处理器合并相邻的字符数据。
isNamespaceAware 关闭名称空间支持。所有实现都必须支持名称空间。支持非命名空间感知文档是可选的。
isReplacingEntityReferences (必需)要求处理器用其替换值替换内部实体引用,并将它们报告为描述实体的字符或事件集。
isSupportingExternalEntities (必填)要求处理器解析外部解析的实体。
记者 (必需)设置并获取XMLReporter接口的实现。
旋转变压器 (必需)设置并获取XMLResolver接口的实现。
分配器 (必需)设置并获取XMLEventAllocator接口的实现。

XMLOutputFactory

抽象类XMLOutputFactory的新实例是通过调用类上的newInstance方法创建的。然后使用静态方法XMLOutputFactory.newInstance创建新的工厂实例。用于获取实例的算法与XMLInputFactory相同,但引用javax.xml.stream.XMLOutputFactory系统属性。

XMLOutputFactory仅支持一个属性, javax.xml.stream.isRepairingNamespaces 。此属性是必需的,其目的是创建默认前缀并将它们与名称空间 URI 相关联。有关更多信息,请参阅 StAX 规范。

XMLEventFactory

抽象类XMLEventFactory的新实例是通过调用类上的newInstance方法创建的。然后使用静态方法XMLEventFactory.newInstance创建新的工厂实例。该工厂引用javax.xml.stream.XMLEventFactory属性来实例化工厂。用于获取实例的算法与XMLInputFactoryXMLOutputFactory相同,但引用javax.xml.stream.XMLEventFactory系统属性。

XMLEventFactory没有默认属性。

资源,命名空间和错误

StAX 规范处理资源解析,属性和命名空间以及错误和异常,如下所述。

资源分辨率

XMLResolver接口提供了一种设置在 XML 处理期间解析资源的方法的方法。应用程序在XMLInputFactory上设置接口,然后在该工厂实例创建的所有处理器上设置接口。

属性和命名空间

属性由 StAX 处理器使用游标接口中的查找方法和字符串以及迭代器接口中的属性命名空间事件进行报告。请注意,命名空间被视为属性,尽管命名空间与游标和迭代器 API 中的属性分开报告。另请注意,对于 StAX 处理器,名称空间处理是可选的。有关命名空间绑定和可选命名空间处理的完整信息,请参阅 StAX 规范。

错误报告和异常处理

通过javax.xml.stream.XMLStreamException接口报告所有致命错误。使用javax.xml.stream.XMLReporter接口报告所有非致命错误和警告。

阅读 XML 流

如本课程前面所述,使用 StAX 处理器读取 XML 流的方式 - 更重要的是,您获得的内容 - 根据您使用的是 StAX 游标 API 还是事件迭代器 API 而有很大差异。以下两节介绍如何使用这些 API 读取 XML 流。

使用 XMLStreamReader

StAX 游标 API 中的XMLStreamReader接口允许您仅向前读取 XML 流或文档,一次只能在信息集中读取一个项目。以下方法可用于从流中提取数据或跳过不需要的事件:

  • 获取属性的值

  • 阅读 XML 内容

  • 确定元素是否包含内容或为空

  • 获取对属性集合的索引访问权限

  • 获取对命名空间集合的索引访问权限

  • 获取当前事件的名称(如果适用)

  • 获取当前事件的内容(如果适用)

XMLStreamReader的实例在任何时候都有一个当前事件,其方法在其上运行。当您在流上创建XMLStreamReader的实例时,初始当前事件是START_DOCUMENT状态。然后可以使用XMLStreamReader.next方法步进到流中的下一个事件。

读取属性,属性和命名空间

XMLStreamReader.next方法加载流中下一个事件的属性。然后,您可以通过调用XMLStreamReader.getLocalNameXMLStreamReader.getText方法来访问这些属性。

XMLStreamReader游标位于StartElement事件上时,它会读取事件的名称和任何属性,包括命名空间。可以使用索引值访问事件的所有属性,也可以通过名称空间 URI 和本地名称查找。但请注意,只有当前StartEvent上声明的命名空间可用;不维护以前声明的名称空间,并且不会删除重新声明的名称空间。

XMLStreamReader 方法

XMLStreamReader提供以下方法来检索有关命名空间和属性的信息:

  1. int getAttributeCount();
  2. String getAttributeNamespace(int index);
  3. String getAttributeLocalName(int index);
  4. String getAttributePrefix(int index);
  5. String getAttributeType(int index);
  6. String getAttributeValue(int index);
  7. String getAttributeValue(String namespaceUri, String localName);
  8. boolean isAttributeSpecified(int index);

也可以使用另外三种方法访问命名空间:

  1. int getNamespaceCount();
  2. String getNamespacePrefix(int index);
  3. String getNamespaceURI(int index);

实例化 XMLStreamReader

此示例取自 StAX 规范,显示了如何实例化输入工厂,创建读取器以及迭代 XML 流的元素:

  1. XMLInputFactory f = XMLInputFactory.newInstance();
  2. XMLStreamReader r = f.createXMLStreamReader( ... );
  3. while(r.hasNext()) {
  4. r.next();
  5. }

使用 XMLEventReader

StAX 事件迭代器 API 中的XMLEventReader API 提供了将 XML 流中的事件映射到可以自由重用的已分配事件对象的方法,并且可以扩展 API 本身来处理自定义事件。

XMLEventReader提供了四种迭代解析 XML 流的方法:

  • next :返回流中的下一个事件

  • nextEvent :返回下一个键入的 XMLEvent

  • hasNext :如果要在流中处理更多事件,则返回 true

  • peek :返回事件但不迭代到下一个事件

例如,以下代码片段说明了XMLEventReader方法声明:

  1. package javax.xml.stream;
  2. import java.util.Iterator;
  3. public interface XMLEventReader extends Iterator {
  4. public Object next();
  5. public XMLEvent nextEvent() throws XMLStreamException;
  6. public boolean hasNext();
  7. public XMLEvent peek() throws XMLStreamException;
  8. // ...
  9. }

要读取流上的所有事件然后打印它们,您可以使用以下内容:

  1. while(stream.hasNext()) {
  2. XMLEvent event = stream.nextEvent();
  3. System.out.print(event);
  4. }

阅读属性

您可以从关联的javax.xml.stream.StartElement访问属性,如下所示:

  1. public interface StartElement extends XMLEvent {
  2. public Attribute getAttributeByName(QName name);
  3. public Iterator getAttributes();
  4. }

您可以使用StartElement接口上的getAttributes方法,在StartElement上声明的所有属性上使用Iterator

读取命名空间

与读取属性类似,使用通过调用StartElement接口上的getNamespaces方法创建的迭代器来读取命名空间。仅返回当前StartElement的命名空间,并且应用程序可以使用StartElement.getNamespaceContext获取当前命名空间上下文。

编写 XML 流

StAX 是一个双向 API,游标和事件迭代器 API 都有自己的一组用于编写 XML 流的接口。与用于读取流的接口一样,游标和事件迭代器的编写器 API 之间存在显着差异。以下部分描述了如何使用这些 API 编写 XML 流。

使用 XMLStreamWriter

StAX 游标 API 中的XMLStreamWriter接口允许应用程序写回 XML 流或创建全新的流。 XMLStreamWriter 有一些方法可以让你:

  • 编写格式良好的 XML

  • 冲洗或关闭输出

  • 写限定名称

请注意, XMLStreamWriter实现不需要对输入执行格式良好或有效性检查。虽然某些实现可能会执行严格的错误检查,但其您实现的规则适用于XMLOutputFactory类中定义的属性。

writeCharacters方法用于转义&amp;等字符。<>。绑定前缀可以通过传递前缀的实际值,使用setPrefix方法,或通过设置默认名称空间声明的属性来处理。

以下示例取自 StAX 规范,演示了如何实例化输出工厂,创建编写器以及编写 XML 输出:

  1. XMLOutputFactory output = XMLOutputFactory.newInstance();
  2. XMLStreamWriter writer = output.createXMLStreamWriter( ... );
  3. writer.writeStartDocument();
  4. writer.setPrefix("c","http://c");
  5. writer.setDefaultNamespace("http://c");
  6. writer.writeStartElement("http://c","a");
  7. writer.writeAttribute("b","blah");
  8. writer.writeNamespace("c","http://c");
  9. writer.writeDefaultNamespace("http://c");
  10. writer.setPrefix("d","http://c");
  11. writer.writeEmptyElement("http://c","d");
  12. writer.writeAttribute("http://c", "chris","fry");
  13. writer.writeNamespace("d","http://c");
  14. writer.writeCharacters("Jean Arp");
  15. writer.writeEndElement();
  16. writer.flush();

此代码生成以下 XML(新行是非规范的):

  1. <?xml version=’1.0 encoding=’utf-8’?>
  2. <a b="blah" xmlns:c="http://c" xmlns="http://c">
  3. <d:d d:chris="fry" xmlns:d="http://c"/>Jean Arp</a>

使用 XMLEventWriter

StAX 事件迭代器 API 中的XMLEventWriter接口允许应用程序写回 XML 流或创建全新的流。此 API 可以扩展,但主要 API 如下:

  1. public interface XMLEventWriter {
  2. public void flush() throws XMLStreamException;
  3. public void close() throws XMLStreamException;
  4. public void add(XMLEvent e) throws XMLStreamException;
  5. // ... other methods not shown.
  6. }

XMLEventWriter的实例由XMLOutputFactory的实例创建。迭代地添加流事件,并且在将事件添加到事件编写器实例之后不能修改事件。

属性,转义字符,绑定前缀

需要 StAX 实现来缓冲最后一个StartElement ,直到在流中添加或遇到属性命名空间以外的事件。这意味着当您将属性命名空间添加到流时,它会附加到当前StartElement事件。

您可以使用字符方法转义&amp;<>

setPrefix(...)方法可用于显式绑定输出期间使用的前缀, getPrefix(...)方法可用于获取当前前缀。请注意,默认情况下, XMLEventWriter会将命名空间绑定添加到其内部命名空间映射中。对于绑定它们的事件,前缀超出了相应的EndElement之后的范围。