StAX API
原文: https://docs.oracle.com/javase/tutorial/jaxp/stax/api.html
StAX API 公开了用于迭代,基于事件的 XML 文档处理的方法。 XML 文档被视为过滤的一系列事件,并且信息集状态可以以过程方式存储。此外,与 SAX 不同,StAX API 是双向的,可以读取和写入 XML 文档。
StAX API 实际上是两个不同的 API 集:游标 API 和迭代器 API。本课程后面将更详细地介绍这两个 API 集,但下面将简要介绍它们的主要功能。
游标 API
顾名思义,StAX 游标 API 代表一个游标,您可以使用该游标从头到尾遍历 XML 文档。这个光标可以一次指向一个东西,并且始终向前移动,从不向后移动,通常一次移动一个信息集元素。
两个主要的游标接口是XMLStreamReader和XMLStreamWriter 。 XMLStreamReader包括可从 XML 信息模型检索的所有可能信息的访问器方法,包括文档编码,元素名称,属性,命名空间,文本节点,开始标记,注释,处理指令,文档边界等等;例如:
public interface XMLStreamReader {public int next() throws XMLStreamException;public boolean hasNext() throws XMLStreamException;public String getText();public String getLocalName();public String getNamespaceURI();// ... other methods not shown}
您可以在XMLStreamReader上调用方法,例如getText和getName ,以获取当前光标位置的数据。 XMLStreamWriter提供与StartElement和EndElement事件类型相对应的方法;例如:
public interface XMLStreamWriter {public void writeStartElement(String localName) throws XMLStreamException;public void writeEndElement() throws XMLStreamException;public void writeCharacters(String text) throws XMLStreamException;// ... other methods not shown}
游标 API 以多种方式镜像 SAX。例如,方法可用于直接访问字符串和字符信息,整数索引可用于访问属性和名称空间信息。与 SAX 一样,游标 API 方法将 XML 信息作为字符串返回,从而最大限度地减少了对象分配要求。
迭代器 API
StAX 迭代器 API 将 XML 文档流表示为一组离散事件对象。这些事件由应用程序提取,并由解析器按照在源 XML 文档中读取它们的顺序提供。
基本迭代器接口称为XMLEvent , XMLEvent 表中列出的每种事件类型都有子接口。用于读取迭代器事件的主要解析器接口是XMLEventReader ,用于编写迭代器事件的主要接口是XMLEventWriter 。 XMLEventReader接口包含五种方法,其中最重要的是nextEvent ,它返回 XML 流中的下一个事件。 XMLEventReader实现了java.util.Iterator ,这意味着来自XMLEventReader的返回可以被缓存或传递到可以与标准 Java Iterator 一起使用的例程中;例如:
public interface XMLEventReader extends Iterator {public XMLEvent nextEvent() throws XMLStreamException;public boolean hasNext();public XMLEvent peek() throws XMLStreamException;// ...}
类似地,在迭代器 API 的输出端,您有:
public interface XMLEventWriter {public void flush() throws XMLStreamException;public void close() throws XMLStreamException;public void add(XMLEvent e) throws XMLStreamException;public void add(Attribute attribute) throws XMLStreamException;// ...}
迭代器事件类型
XMLEvent Types Defined in the Event Iterator API
| 事件类型 | 描述 |
|---|---|
StartDocument |
报告一组 XML 事件的开始,包括编码,XML 版本和独立属性。 |
StartElement |
报告元素的开始,包括任何属性和名称空间声明;还可以访问开始标记的前缀,名称空间 URI 和本地名称。 |
EndElement |
报告元素的结束标记。如果已在相应的StartElement上明确设置了超出范围的命名空间,则可以在此处调用它们。 |
Character |
对应于 XML CData部分和CharacterData实体。请注意,可忽略的空白区域和显着的空白区域也会报告为Character事件。 |
EntityReference |
可以将字符实体报告为离散事件,然后应用程序开发人员可以选择解析或通过未解析的事件。默认情况下,实体已解析。或者,如果您不想将实体报告为事件,则可替换替换文本并将其报告为字符。 |
ProcessingInstruction |
报告基础处理指令的目标和数据。 |
评论 |
返回注释的文本。 |
EndDocument |
报告一组 XML 事件的结束。 |
DTD |
报告java.lang.String有关与流关联的 DTD 信息(如果有),并提供返回 DTD 中找到的自定义对象的方法。 |
属性 |
属性通常作为StartElement事件的一部分报告。但是,有时需要将属性作为独立的属性事件返回;例如,当XQuery或XPath表达式返回命名空间时。 |
命名空间 |
与属性一样,命名空间通常作为StartElement的一部分进行报告,但有时需要将命名空间报告为离散命名空间事件。 |
请注意, DTD , EntityDeclaration , EntityReference , NotationDeclaration和ProcessingInstruction事件仅在文档中创建正在处理包含 DTD。
事件映射示例
作为事件迭代器 API 如何映射 XML 流的示例,请考虑以下 XML 文档:
<?xml version="1.0"?><BookCatalogue xmlns="http://www.publishing.org"><Book><Title>Yogasana Vijnana: the Science of Yoga</Title><ISBN>81-40-34319-4</ISBN><Cost currency="INR">11.50</Cost></Book></BookCatalogue>
该文档将被分析为十八个主要和次要事件,如下表所示。请注意,大括号( {} )中显示的辅助事件通常是从主事件而不是直接访问的。
Example of Iterator API Event Mapping
| # | 元素/属性 | 事件 |
|---|---|---|
| 1 | version="1.0" |
StartDocument |
| 2 | isCData = false data = "\n" IsWhiteSpace = true |
Character |
| 3 | qname = BookCatalogue:http://www.publishing.org attributes = null namespaces = {BookCatalogue" -> http://www.publishing.org"} |
StartElement |
| 4 | qname = Book attributes = null namespaces = null |
StartElement |
| 五 | qname = Title attributes = null namespaces = null |
StartElement |
| 6 | isCData = false data = "Yogasana Vijnana: the Science of Yoga\n\t" IsWhiteSpace = false |
Character |
| 7 | qname = Title namespaces = null |
EndElement |
| 8 | qname = ISBN attributes = null namespaces = null |
StartElement |
| 9 | isCData = false data = "81-40-34319-4\n\t" IsWhiteSpace = false |
Character |
| 10 | qname = ISBN namespaces = null |
EndElement |
| 11 | qname = Cost attributes = {"currency" -> INR} namespaces = null |
StartElement |
| 12 | isCData = false data = "11.50\n\t" IsWhiteSpace = false |
Character |
| 13 | qname = Cost namespaces = null |
EndElement |
| 14 | isCData = false data = "\n" IsWhiteSpace = true |
Character |
| 15 | qname = Book namespaces = null |
EndElement |
| 16 | isCData = false data = "\n" IsWhiteSpace = true |
Character |
| 17 | qname = BookCatalogue:http://www.publishing.org namespaces = {BookCatalogue" -> http://www.publishing.org"} |
EndElement |
| 18 | EndDocument |
在这个例子中有几点需要注意:
事件按照文档中遇到相应 XML 元素的顺序创建,包括元素嵌套,元素的打开和关闭,属性顺序,文档开始和文档结束等。
与适当的 XML 语法一样,所有容器元素都有相应的开始和结束事件;例如,每个
StartElement都有一个相应的EndElement,即使对于空元素也是如此。属性事件被视为次要事件,并从相应的StartElement事件中访问。与
属性事件类似,名称空间事件被视为次要事件,但出现两次并且在事件流中可访问两次,首先来自其对应的StartElement,然后从他们对应的EndElement。为所有元素指定了字符事件,即使这些元素没有字符数据。类似地,Character事件可以跨事件分割。StAX 解析器维护一个名称空间堆栈,该堆栈包含有关为当前元素及其祖先定义的所有 XML 名称空间的信息。通过
javax.xml.namespace.NamespaceContext接口公开的命名空间堆栈可以通过命名空间前缀或 URI 访问。
在 Cursor 和 Iterator API 之间进行选择
在这一点上提出“我应该选择什么 API?我应该创建XMLStreamReader或XMLEventReader的实例吗?为什么还有两种 API 呢?“
发展目标
StAX 规范的作者针对三种类型的开发人员:
图书馆和基础设施开发人员:创建应用服务器,JAXM,JAXB,JAX-RPC 和类似的实现;需要高效,低级的 API,并且可扩展性要求最低。
Java ME 开发人员:需要小型,简单的拉解析库,并且具有最小的可扩展性需求。
Java 平台,企业版(Java EE)和 Java 平台,标准版(Java SE)开发人员:需要干净,高效的拉解析库,需要灵活地读取和写入 XML 流,创建新的事件类型,并扩展 XML 文档元素和属性。
鉴于这些广泛的开发类别,StAX 作者认为定义两个小而有效的 API 更有用,而不是重载一个更大且必然更复杂的 API。
比较 Cursor 和 Iterator API
在光标和迭代器 API 之间进行选择之前,您应该注意一些可以使用游标 API 无法执行的迭代器 API:
从
XMLEvent子类创建的对象是不可变的,可以在数组,列表和映射中使用,甚至在解析器转移到后续事件之后也可以通过您的应用程序传递。您可以创建
XMLEvent的子类型,它们是完全新的信息项或现有项的扩展,但使用其他方法。您可以使用比游标 API 更简单的方式在 XML 事件流中添加和删除事件。
同样,在做出选择时,请记住一些一般性建议:
如果您正在为特定于内存的环境(如 Java ME)编程,则可以使用游标 API 生成更小,更高效的代码。
如果性能是您的最高优先级 - 例如,在创建低级库或基础结构时 - 游标 API 更有效。
如果要创建 XML 处理管道,请使用迭代器 API。
如果要修改事件流,请使用迭代器 API。
如果希望应用程序能够处理事件流的可插入处理,请使用迭代器 API。
通常,如果您没有强烈的偏好,建议使用迭代器 API,因为它更灵活和可扩展,从而“面向未来”您的应用程序。
