以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 DTD/XML Schema 』  (http://bbs.xml.org.cn/list.asp?boardid=23)
----  [推荐]技巧: 使用 StAX 编写 XML 文档  (http://bbs.xml.org.cn/dispbbs.asp?boardid=23&rootid=&id=11926)


--  作者:anchen0617
--  发布时间:11/9/2004 3:20:00 PM

--  [推荐]技巧: 使用 StAX 编写 XML 文档
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 文档。


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
39.063ms