XML解析的三种方式

 


高效解析XML是任何一个优秀的编码框架所必须包含的一块功能。在Java的世界当中,有三种处理XML的方式:DOM, SAX, StAX。网上对这三种解析模式也有了大量的说明。那么这三种解析方式在实际使用时到底各有什么特点呢?让我们通过三个实例来进行横向的比较。

首先我们创建一个xml文件,命名为 data.xml

1<?xml version="1.0" encoding="UTF-8"?>
2<greetings>
3    <greeting id="g1">Hello DOM</greeting>
4    <greeting id="g2">Hello SAX</greeting>
5    <greeting id="g3">Hello StAX</greeting>
6</greetings>

首先我们用DOM方式来解析这个XML。DOM的特点是一次性把XML读进内存,并按下图所示DOM结构将XML数据映射成Java对象:

下面这段代码调用 org.w3c.dom.* 来解析xml:

01package org.bluedash;
02 
03import javax.xml.parsers.DocumentBuilder;
04import javax.xml.parsers.DocumentBuilderFactory;
05import org.w3c.dom.Document;
06import org.w3c.dom.Element;
07import org.w3c.dom.NamedNodeMap;
08import org.w3c.dom.Node;
09import org.w3c.dom.NodeList;
10 
11public class TryDom {
12    public static void main(String args[]) throws Exception {
13        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
14        DocumentBuilder builder = factory.newDocumentBuilder();
15        Document doc = builder.parse(“data.xml”);
16        Element elem = doc.getDocumentElement();
17        NodeList list = elem.getChildNodes();
18        for (int i = 0; i < list.getLength(); i++) {
19            Node node = list.item(i);
20            NamedNodeMap attributes = node.getAttributes();
21            if (attributes != null) {
22                for (int j = 0; j < attributes.getLength(); j++) {
23                    Node attr = attributes.item(j);
24                    System.out.println("attr name: " + attr.getNodeName());
25                    System.out.println("attr value: " + attr.getNodeValue());
26                }
27            }
28            System.out.println("node name: " + node.getNodeName());
29            System.out.println("node type: " + node.getNodeType());
30            System.out.println("node value: " + node.getNodeType());
31            System.out.println("content: " + node.getTextContent());
32            System.out.println(“—————————”);
33        }
34    }
35}

代码输出结果如下:

01node name: #text
02node type: 3
03node value: 3
04content:
05     
06---------------------
07attr name: id
08attr value: g1
09node name: greeting
10node type: 1
11node value: 1
12content: Hello DOM
13---------------------
14node name: #text
15node type: 3
16node value: 3
17content:
18     
19---------------------
20attr name: id
21attr value: g2
22node name: greeting
23node type: 1
24node value: 1
25content: Hello SAX
26---------------------
27node name: #text
28node type: 3
29node value: 3
30content:
31     
32---------------------
33attr name: id
34attr value: g3
35node name: greeting
36node type: 1
37node value: 1
38content: Hello StAX
39---------------------
40node name: #text
41node type: 3
42node value: 3
43content:
44 
45---------------------

请注意 node type: 3 是代表的是空格。DOM会把greeting元素间的空白也算做独立的内容。通过上述样例我们可以发现DOM的特点就是一次性把XML数据读入内存并按照DOM约定的结构创建相关的实例。对于尺寸较小的XML文件,使用DOM来进行解析还是非常方便的,但如果XML的文件尺寸比较大,用DOM方式进行解析的效率就比较低,对内存资源的浪费也比较大,因此我们需要以"流"1的方式来解析XML。SAX和StAX正是这样的工具。

首先来看SAX:

01package org.bluedash;
02 
03import java.io.File;
04import java.io.FileInputStream;
05import java.io.InputStreamReader;
06 
07import javax.xml.parsers.SAXParser;
08import javax.xml.parsers.SAXParserFactory;
09 
10import org.xml.sax.AttributeList;
11import org.xml.sax.HandlerBase;
12import org.xml.sax.InputSource;
13import org.xml.sax.SAXException;
14 
15public class TrySAX extends HandlerBase {
16 
17    @Override
18    public void characters(char[] ch, int start, int length)
19            throws SAXException {
20        String value = new String(ch, start, length);
21        if (!value.trim().equals("")) {
22            System.out.println("Text: " + value);
23        }
24    }
25 
26    @Override
27    public void endDocument() throws SAXException {
28        System.out.println("End Document");
29        super.endDocument();
30    }
31 
32    @Override
33    public void endElement(String name) throws SAXException {
34        System.out.println("End Element:" + name);
35        super.endElement(name);
36    }
37 
38    @Override
39    public void startDocument() throws SAXException {
40        System.out.println("Start Document.");
41        super.startDocument();
42    }
43 
44    @Override
45    public void startElement(String name, AttributeList attributes)
46            throws SAXException {
47        System.out.println("Start Element: " + name);
48        for (int i = 0, n = attributes.getLength(); i < n; ++i)
49            System.out.println("Attribute: " + attributes.getName(i) +"="
50                    + attributes.getValue(i));
51        super.startElement(name, attributes);
52    }
53 
54    public static void main(String args[]) throws Exception {
55        InputStreamReader reader = new InputStreamReader(newFileInputStream(
56                new File("data.xml")));
57 
58        InputSource source = new InputSource(reader);
59        HandlerBase handler = new TrySAX();
60 
61        SAXParserFactory factory = SAXParserFactory.newInstance();
62        String parserClassName = "javax.xml.parsers.SAXParser";
63        SAXParser parser = factory.newSAXParser();
64 
65        parser.parse(source, handler);
66 
67    }
68}

执行上述程序,结果输出如下:

01Start Document.
02Start Element: greetings
03Start Element: greeting
04Attribute: id=g1
05Text: Hello DOM
06End Element:greeting
07Start Element: greeting
08Attribute: id=g2
09Text: Hello SAX
10End Element:greeting
11Start Element: greeting
12Attribute: id=g3
13Text: Hello StAX
14End Element:greeting
15End Element:greetings
16End Document

SAX方式把XML用流的方式读入,并在把XML的相关元素分解成一系列事件。当遇见某一事件时,触发这个事件对应的方法。SAX的事件模型如下:

这样,我们在事件对应的方法中,撰写我们所需的业务处理逻辑即可。但这样写程序有点怪,我们的业务逻辑代码必须要封装到这些事件所在的 HandlerBase 中,而不是我们所期望的业务逻辑的Class当中。我们称这样的封装方法为“推送”2的方法。

那么有没有可能,我们不把业务逻辑放在事件方法中,而是我们调用 Handler 来处理XML呢?答案是有,StAX就是以后一种形式工作的。与SAX不同,StAX采用"拉"3的方法来处理XML。也是通过一段样例来说明StAX的使用方法:

01package org.bluedash;
02 
03import java.io.FileInputStream;
04import java.io.IOException;
05import java.io.InputStream;
06 
07import javax.xml.stream.XMLInputFactory;
08import javax.xml.stream.XMLStreamConstants;
09import javax.xml.stream.XMLStreamException;
10import javax.xml.stream.XMLStreamReader;
11 
12public class TryCursorMode {
13 
14    private void parseXML() throws IOException, XMLStreamException {
15 
16        InputStream in = new FileInputStream("data.xml");
17        XMLInputFactory inFactory = XMLInputFactory.newInstance();
18        XMLStreamReader r = inFactory.createXMLStreamReader(in);
19 
20        try {
21            int event = r.getEventType();
22            while (true) {
23                switch (event) {
24                case XMLStreamConstants.START_DOCUMENT:
25                    System.out.println("Start Document.");
26                    break;
27                case XMLStreamConstants.START_ELEMENT:
28                    System.out.println("Start Element: " + r.getName());
29                    for (int i = 0, n = r.getAttributeCount(); i < n; ++i)
30                        System.out.println("Attribute: "
31                                + r.getAttributeName(i) + "="
32                                + r.getAttributeValue(i));
33 
34                    break;
35                case XMLStreamConstants.CHARACTERS:
36                    if (r.isWhiteSpace())
37                        break;
38 
39                    System.out.println("Text: " + r.getText());
40                    break;
41                case XMLStreamConstants.END_ELEMENT:
42                    System.out.println("End Element:" + r.getName());
43                    break;
44                case XMLStreamConstants.END_DOCUMENT:
45                    System.out.println("End Document.");
46                    break;
47                }
48 
49                if (!r.hasNext())
50                    break;
51 
52                event = r.next();
53            }
54        finally {
55            r.close();
56        }
57 
58    }
59 
60    public static void main(String args[]) throws Exception {
61        TryCursorMode demo = new TryCursorMode();
62        demo.parseXML();
63 
64    }
65}

执行这段程序,我们可以得到结果如下:

01Start Document.
02Start Element: greetings
03Start Element: greeting
04Attribute: id=g1
05Text: Hello DOM
06End Element:greeting
07Start Element: greeting
08Attribute: id=g2
09Text: Hello SAX
10End Element:greeting
11Start Element: greeting
12Attribute: id=g3
13Text: Hello StAX
14End Element:greeting
15End Element:greetings
16End Document.

可以看到,StAX的API的设计思路与SAX是非常不同的,通过StAX,处理XML的逻辑被转移到了我们自己的主逻辑代码中。

通过以上三段代码,我们可以看到三种XML的处理方式的区别。有关这三种方式,还有非常详细深入的话题可以展开,如果有兴趣进一步学习,可以查看参考资料中的相关内容。

参考资料:

  1. Using DOM to Traverse XML – http://onjava.com/pub/a/onjava/2001/02/08/dom.html
  2. SAX Tutorial 1 – http://developerlife.com/tutorials/?p=29
  3. Using the SAX Parser – http://www.javacommerce.com/displaypage.jsp?name=saxparser1.sql&id=18232
  4. StAX’ing up XML, Part 1: An introduction to Streaming API for XML (StAX) –http://www.ibm.com/developerworks/xml/library/x-stax1.html
  5. Tip: Parsing XML documents partially with StAX –http://www.ibm.com/developerworks/xml/library/x-tipstx2/
  6. An Introduction to StAX – http://www.xml.com/pub/a/2003/09/17/stax.html

注解:

1 Stream

2 push

3 pull

 


liweinan  2010-03-26 07:00PM

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值