Streaming API for XML (StAX) 不仅能解析 XML 文档,而且可以把 XML 文档写入一个输出流。这篇技巧展示了客户应用程序如何使用底层的、基于指针的 StAX API 有效地创建 XML 文档。
直到最近,程序员通过编程创建 XML 文档还只有两种选择。一种是把序列化的 XML 内容写入输出流,第二种是使用 DOM。
这 两种方法都有严重的缺陷。对于第一种情况,程序员完全负责保证结果文档是格式正规的。程序员必须处理其中的细节,比如起始标签和结束标签的匹配,以及字符 内容中特殊字符的转义,如小于号(<)和逻辑与(&)。这可能造成程序的实现冗长乏味而且容易出错。另一方面,尽管 DOM 把程序员从这种沉重的负担中解放出来,但是引入了巨大的开销:在序列化到输出流之前,整个文档必须首先在内存中构造一棵节点树。
Streaming API for XML (StAX) 彻底改变这一切。与 Simple API for XML (SAX) 不同,StAX 提供了编写 XML 文档的 API。更具体地说,它提供了两种 API:底层的、基于指针的 API( XMLStreamWriter
)和高级的、基于事件的 API( XMLEventWriter
)。基于指针的 API 最适合用于数据绑定的情况(比如从应用程序数据创建文档),而基于事件的 API 则通常用于管道式的情况,从输入文档中的数据构造新的文档。
下面的例子是使用基于指针的 API 实现的。(我将在下篇技巧中讨论基于事件的 API。)基于指针的 API 为创建 XML 信息集中的不同元素提供了各种专门的方法,比如元素、属性、处理指令、数据类型声明和字符内容。这些方法解决了许多格式化问题。比如, writeCharacters()
方法自动转义像小于号(<)、大于号(>)和逻辑与(&)这样的特殊字符。而 writeEndDocument()
则自动关闭所有打开的结构。因此即使把本例中最后一次对 writeEndElement()
的调用注释掉也没有关系。
StAX 甚至可以为没有正式声明的名称空间生成名称空间前缀。但是只有在输出工厂的 javax.xml.stream.isPrefixDefaulting
属性设为 true
时才会这么做。如果该属性被设为 false
,您就必须明确地声明每个名称空间前缀,并对每个名称空间使用 setPrefix()
和 writeNamespace()
方法。清单 1 中,我已经把这些方法调用注释掉了,因为我已经把前缀默认设置为 true
。
清单 1. 编写文档
import javax.xml.stream.*; |
注意,StAX 不能保证文档的格式正规性。仍然可能生成违反 XML 推荐标准的文档,比如一个文档中有多个根元素或者多个 XML 序言,标签名和属性名中包含空格或 XML 不支持的字符。StAX 实现可以检查这些问题,但并不要求这么做(参考实现中就没有这样做)。尽管如此,StAX XMLStreamWriter
对于输出原始 XML 数据仍然是一个很大的改进,而且开销只是 DOM 的一个零头。
|
这篇技巧说明了如何使用 StAX 基于指针的 API 有效地编写 XML 文档。在下一篇文章中,我将介绍如何使用基于事件的 API 合并两个 XML 文档。
没有评论:
发表评论