首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 StAX 编写 XML 文档

使用 StAX 编写 XML 文档

直到最近,程序员通过编程创建 XML 文档还只有两种选择。一种是把序列化的 XML 内容写入输出流,第二种是使用 DOM。
这两种方法都有严重的缺陷。对于第一种情况,程序员完全负责保证结果文档是格式正规的。程序员必须处理其中的细节,比如起始标签和结束标签的匹配,以及字符内容中特殊字符的转义,如小于号(<)和逻辑与(&)。这可能造成程序的实现冗长乏味而且容易出错。另一方面,尽管 DOM 把程序员从这种沉重的负担中解放出来,但是引入了巨大的开销:在序列化到输出流之前,整个文档必须首先在内存中构造一棵节点树。
进入 StAXStreaming 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. 编写文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import javax.xml.stream.*;
public class XMLWriter {
   // Namespaces
   private static final String GARDENING = "http://com.bdaum.gardening";
   private static final String XHTML = "http://www.w3.org/1999/xhtml";
   public static void main(String[] args) throws XMLStreamException  {
      
      // Create an output factory
      XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
      // Set namespace prefix defaulting for all created writers
      xmlof.setProperty("javax.xml.stream.isPrefixDefaulting",Boolean.TRUE);
      
      // Create an XML stream writer
      XMLStreamWriter xmlw =
         xmlof.createXMLStreamWriter(System.out);
      // Write XML prologue
      xmlw.writeStartDocument();
      // Write a processing instruction
      xmlw.writeProcessingInstruction(
         "xml-stylesheet href='catalog.xsl' type='text/xsl'");
      // Now start with root element
      xmlw.writeStartElement("product");
      // Set the namespace definitions to the root element
      // Declare the default namespace in the root element
      xmlw.writeDefaultNamespace(GARDENING);
      // Writing a few attributes
      xmlw.writeAttribute("productNumber","3923-1");
      xmlw.writeAttribute("name","Nightshadow");
      // Declare XHTML prefix
//    xmlw.setPrefix("xhtml",XHTML);
      // Different namespace for description element
      xmlw.writeStartElement(XHTML,"description");
      // Declare XHTML namespace in the scope of the description element
//    xmlw.writeNamespace("xhtml",XHTML);
      xmlw.writeCharacters(
         "A tulip of almost black color. \nBlossoms in April & May");
      xmlw.writeEndElement();
      // Shorthand for empty elements
      xmlw.writeEmptyElement("supplier");
      xmlw.writeAttribute("name","Floral22");
//    xmlw.writeEndElement();
      // Write document end. This closes all open structures
      xmlw.writeEndDocument();
      // Close the writer to flush the output
      xmlw.close();
   }
}




注意,StAX 不能保证文档的格式正规性。仍然可能生成违反 XML 推荐标准的文档,比如一个文档中有多个根元素或者多个 XML 序言,标签名和属性名中包含空格或 XML 不支持的字符。StAX 实现可以检查这些问题,但并不要求这么做(参考实现中就没有这样做)。尽管如此,StAX         XMLStreamWriter 对于输出原始 XML 数据仍然是一个很大的改进,而且开销只是 DOM 的一个零头。      
结束语这篇技巧说明了如何使用 StAX 基于指针的 API 有效地编写 XML 文档。在下一篇文章中,我将介绍如何使用基于事件的 API 合并两个 XML 文档。
返回列表