Tuesday, April 23, 2013

使用SAX来解析XML

在JAVA开发中有很多XML的解析API.也有很多开源工具,我以前使用最多的是apache的digester.他功能强大.应用了事件驱动的模式.可以根据rule来分别处理每一个Tag的内容.
后来研究了一下sax, 发现这已经够用了.因为一般的小应用都是把xml作为数据传输.很少用到dtd等.
这并不是介绍digester.而是介绍有java的基本API. 他就是SAX. 使用SAX就不需要额外添加包.这对于Android的开发来说会带来一定的方便,
至于DOM是一个面向树结果的xml的处理.用过程式的方式处理.代码的耦合程度高.不在讨论的范围内.
先看例程:
package com.saxtest.test;

import java.io.FileInputStream;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class XmlParseTest {
    public static void main(String[] args) throws SAXException, IOException, ParserConfigurationException {
        FileInputStream in=new FileInputStream("d:/test.xml");

        SAXParserFactory spf=SAXParserFactory.newInstance();
        SAXParser parser=spf.newSAXParser();
        parser.parse(in, new MyHandler());
        in.close();
    }
}

class MyHandler extends DefaultHandler{
    private int space=0;
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        for(int i=0;i<space;i++){
            System.out.print('\t');
        }
        System.out.println(qName+' '+attributes.getValue("title"));
        space ++;
    }
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        space --;
    }
    @Override
    public void characters(char[] buf, int start, int length) throws SAXException {
        StringBuilder sb=new StringBuilder();
        boolean hasContent=false;
        for(int i=0;i<length;i++){
            if(buf[start+i]=='\n')continue;
            hasContent=true;
            sb.append(buf[start+i]);
        }
        if(hasContent){
            for(int i=0;i<space;i++){
                System.out.print('\t');
            }

            System.out.println(sb);
        }
    }
    @Override
    public void endDocument() throws SAXException {
        // TODO Auto-generated method stub
        super.endDocument();
    }
    @Override
    public void startDocument() throws SAXException {
        // TODO Auto-generated method stub
        super.startDocument();
    }
}
基本上对于XML的处理.都可以向main方法一样不用什么变化,主要业务在MyHandler中.只需要2个方法(startElement,endElement)就把xml树中的所有节点迭代出来了.而且并不需要递归迭代.极大的优化了代码的结构.具体使用看javadoc就有很详细的解释.
SAXParser会处理每一个tag.在tag的开始会调用startElement方法.当tag结束时会调用endElement, 这种设计类似于事件驱动的设计模型.是一种很好的解耦合设计.

No comments:

Post a Comment