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

developerWorks 中国  >  XML  >

技巧: 使用 StAX 高效筛选 XML 文档

检索需要的信息,然后停止解析过程

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

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

2004 年 1 月 01 日

使用 Streaming for XML (StAX),可以避免传统推式解析器的缺陷,从而有效地筛选 XML 文档。这篇技巧展示了如何从 XML 文档中检索特定信息,一旦收集到这些信息即停止解析过程。

XML 文档筛选或者分类是一个常见的问题,特别是在 XML 中间件中。把 XML 文档交给特定的处理器可能需要同时分析文档类型和文档内容。问题在于以尽可能小的代价从文档中取得要求的信息。传统解析器如 DOM 或 SAX 不是非常适合这项工作。比如,DOM 需要解析全部文档并在内存中构造完整的文档树,然后才把控制交给客户。即使采用延后节点展开(因此可以部分解析文档)的 DOM 解析器,也有很高的资源要求,因为至少要在内存中部分构造文档树。出于文档筛选的目的而言,这是完全不能接受的。

和 DOM 类似,SAX 解析器也控制了整个解析过程。默然情况下,SAX 解析器从文档的开始处进行解析直到文件尾结束。在解析过程中,通过回调事件通知客户事件处理程序。在文档筛选中为了避免不必要的开销,这种事件处理程序可能希望在收集到必要的信息后停止解析过程。SAX 实现这种机制的常见技术是抛出异常,这种方法在 Nicholas Chase 的 developerWorks技巧文章“ Stop a SAX parser when you have enough data”中讨论过。这样将导致 SAX 终止解析过程。事件处理程序采集的信息必须编码在一个错误信息中,该错误信息包装在一个异常对象中提交给解析器客户。客户中一个专门的错误处理程序接收这种异常,并且必须在解析器错误消息中检索出需要的信息!这也可以作为筛选文档的一种方法,但这是一种复杂的方法。

进入 StAX

StAX 提供了一个拉式解析器,可以让客户应用程序完全控制解析过程。客户应用程序可以决定何时中止解析过程,让解析器停下来也不需要什么诀窍。对于筛选而言这是非常理想的。

清单 1 说明了一个简单的文档分类程序可能是什么样子。这个例子中我使用了基于指针的 StAX API。从文档的第一个起始标签开始(根元素标签),我从该元素中检索 kind 属性。然后把该属性的值回传给客户,解析过程也停止了。客户现在可以处理这个返回值了。


清单 1. 筛选文档
import java.io.*;
import javax.xml.stream.*;
public class Classifier {
   // Holds factory instance
   private XMLInputFactory xmlif;
   public static void main(String[] args)
      throws FileNotFoundException, XMLStreamException {
      Classifier router = new Classifier();
      String kind1 = router.getKind("somefile.xml");
      String kind2 = router.getKind("otherfile.xml");
   }
   /**
    * Return the document kind
    * @param string - the value of the "kind" attribute of the root element
    */
   private String getKind(String filename)
      throws FileNotFoundException, XMLStreamException {
      // Create input factory lazily
      if (xmlif == null) {
         // Use reference implementation
         System.setProperty(
            "javax.xml.stream.XMLInputFactory",
            "com.bea.xml.stream.MXParserFactory");
         xmlif = XMLInputFactory.newInstance();
      }
      // Create stream reader
      XMLStreamReader xmlr =
         xmlif.createXMLStreamReader(new FileReader(filename));
      // Main event loop
      while (xmlr.hasNext()) {
         // Process single event
         switch (xmlr.getEventType()) {
            // Process start tags
            case XMLStreamReader.START_ELEMENT :
               // Check attributes for first start tag
               for (int i = 0; i < xmlr.getAttributeCount(); i++) {
                  // Get attribute name
                  String localName = xmlr.getAttributeName(i);
                  if (localName.equals("kind")) {
                     // Return value
                     return xmlr.getAttributeValue(i);
                  }
               }
               return null;
         }
         // Move to next event
         xmlr.next();
      }
      return null;
   }
}

注意,我使用了一个实例字段保存 XMLInputFactory 实例。这样做是为了提高效率。和实际的解析过程(要快得多)相比, XMLInputFactory.newInstance()xmlif.createXMLStreamReader() 需要很大的开销。虽然每个文档都要执行一次 createXMLStreamReader() ,但您可以重用 XMLInputFactory 实例,从而避免反复执行 XMLInputFactory.newInstance()





回页首


下一步

这篇技巧说明了如何使用 StAX 解析器筛选和分类 XML 文档。在下一篇技巧中,我将介绍如何通过 StAX 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 联系。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


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