IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML  >

技巧: 使用 StAX 编写 XML 文档

使用底层的、基于指针的 StAX API

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Berthold Daum (berthold.daum@bdaum.de), 总裁, BDaum Industrial Communications

2004 年 1 月 01 日

Streaming API for XML (StAX) 不仅能解析 XML 文档,而且可以把 XML 文档写入一个输出流。这篇技巧展示了客户应用程序如何使用底层的、基于指针的 StAX API 有效地创建 XML 文档。

直到最近,程序员通过编程创建 XML 文档还只有两种选择。一种是把序列化的 XML 内容写入输出流,第二种是使用 DOM。

这两种方法都有严重的缺陷。对于第一种情况,程序员完全负责保证结果文档是格式正规的。程序员必须处理其中的细节,比如起始标签和结束标签的匹配,以及字符内容中特殊字符的转义,如小于号(<)和逻辑与(&)。这可能造成程序的实现冗长乏味而且容易出错。另一方面,尽管 DOM 把程序员从这种沉重的负担中解放出来,但是引入了巨大的开销:在序列化到输出流之前,整个文档必须首先在内存中构造一棵节点树。

进入 StAX

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.*;
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 文档。



参考资料



关于作者

Berthold Daum 是德国 Ltzelbach 的一名顾问和作家。他的近作有 System Architecture with XMLModeling Business Objects with XML Schema(均由 Morgan Kauffman 出版),要了解这些书的更多信息,请访问 http://www.bdaum.de。可以通过 berthold.daum@bdaum.de与 Berthold 联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款