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

使用 StAX 部分解析 XML 文档

使用 StAX 部分解析 XML 文档

解析 XML 文档时,         XMLEventReader 实例通过它的         next() 方法向客户传递事件对象,文档中的每个语法单位都有一个事件。但是,应用程序不一定愿意接受所有的事件类;只查看 XML 元素及其属性的应用程序并不关心代表注释和处理指令的事件。幸运的是,StAX 允许您通过实现事件过滤器忽略某些事件类。      
清单 1 给出了一个忽略所有 XML 处理指令的事件过滤器。这些事件没有传递给事件阅读器的         hasNext() 、         next() 或         peek() 方法。向给定的事件阅读器增加过滤器,必须构造一个新的阅读器,可以通过工厂方法         createFilteredReader() 完成。该方法接收原来的阅读器和         EventFilter 作为参数。接下来我使用这个新的事件过滤阅读器解析文档。      
清单 1. 过滤 XML 事件
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
import java.io.*;
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
public class ParseFilteredByEvent {
   public static void main(String[] args)
      throws FileNotFoundException, XMLStreamException {
      // Use  reference implementation
      System.setProperty(
         "javax.xml.stream.XMLInputFactory",
         "com.bea.xml.stream.MXParserFactory");
      // Create the XML input factory
      XMLInputFactory factory = XMLInputFactory.newInstance();
      // Create event reader
      FileReader reader = new FileReader("somefile.xml");
      XMLEventReader eventReader = factory.createXMLEventReader(reader);
      // Create a filtered reader
      XMLEventReader filteredEventReader =
         factory.createFilteredReader(eventReader, new EventFilter() {
         public boolean accept(XMLEvent event) {
            // Exclude PIs
            return (!event.isProcessingInstruction());
         }
      });
      // Main event loop
      while (filteredEventReader.hasNext()) {
         XMLEvent e = filteredEventReader.next();
         System.out.println(e);
      }
   }
}




用同样的方式,你可以从主应用程序逻辑隐藏其他事件类。您甚至可以通过分层的方式组合几个         EventFilter ,在另一个事件过滤阅读器的基础上构建新的过滤阅读器。      
隐藏文档分支在下面的例子中,我要介绍的过滤器能够忽略 XML 文档的整个分支。这一次我使用基于指针的 API 和流过滤阅读器而不是事件阅读器,因为我发现复杂的过滤器最好用流过滤器实现。与上面的例子类似,新的流过滤阅读器建立在基本流阅读器的基础上:
清单 2. 创建流过滤阅读器
1
2
3
4
5
// Create stream reader
XMLStreamReader xmlr =
   xmlif.createXMLStreamReader(new FileReader("somefile.xml"));
// Create a filtered stream reader
XMLStreamReader xmlfr = xmlif.createFilteredReader(xmlr, filter);




其中第二个参数所用的         StreamFilter 由  给出。在 XML 元素开始和结束的时候,它把相应的元素名和一个路径片段进行比较。路径作为一个         QName 数组实现,指定应该忽略文档的哪些部分。在这个例子中,路径 invoice/item 中的所有元素将被忽略。      
实现这种过滤器必须要知道,每次激活         hasNext() 、         next() 或         peek() 方法时都会调用过滤器的         accept() 方法。因此,同一个事件可能多次调用         accept() 方法。在这里,我保证对每个事件过滤逻辑只执行一次,只有当文档中的字符位置发生变化时才会执行。      
清单 3. 流过滤器
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
// Exclusion path
private static QName[] exclude = new QName[] {
   new QName("invoice"), new QName("item")};
private static StreamFilter filter = new StreamFilter() {
   // Element level
   int depth = -1;
   // Last matching path segment
   int match = -1;
   // Filter result
   boolean process = true;
   // Character position in document
   int currentPos = -1;
   
   public boolean accept(XMLStreamReader reader) {
      // Get character position
      Location loc = reader.getLocation();
      int pos = loc.getCharacterOffset();
      // Inhibit double execution
      if (pos != currentPos) {
         currentPos = pos;
         switch (reader.getEventType()) {
            case XMLStreamConstants.START_ELEMENT :
               // Increment element depth
               if (++depth < exclude.length && match == depth - 1) {
                  // Compare path segment with current element
                  if (reader.getName().equals(exclude[depth]))
                     // Equal - set segment pointer
                     match = depth;
               }
               // Process all elements not in path
               process = match < exclude.length - 1;
               break;
            // End of XML element
            case XMLStreamConstants.END_ELEMENT :
               // Process all elements not in path
               process = match < exclude.length - 1;
               // Decrement element depth
               if (--depth < match)
                  // Update segment pointer
                  match = depth;
               break;
         }
      }
      return process;
   }
};




下一步这篇技巧示范了在 StAX 解析器中使用过滤器。在下一篇技巧中,我将介绍如何利用这些技术和其他技术来有效地筛选(screen)XML 文档。
返回列表