dom解析占用内存大(我这边需要解析各种各样的kml文件,有时4-5M的kml文件使用dom解析很多手机就内存溢出了),也需要引入第三方库,所以使用相对于节省内存很多、不需引入其他库的sax解析就是很好的选择了。因为sax解析比较复杂的xml文件特别麻烦,所以整理了一个简化android sax解析的工具。

  实现思路:和Android Touch事件传递机制一样,把需要子解析器解析的节点往下传递。

  如果有进一步简化的方法,欢迎交流!email:csqwyyx@163.com。

  示例程序:https://github.com/John-Chen/EasySaxParser

 

  简化工具SaxParser:

public abstract class SaxParser {

    protected String curQName;
    protected StringBuilder curValue = new StringBuilder();

    protected SaxParser saxParser;
    protected String saxParserQName;

    /**
     * 需要生成子SaxParser的节点名称
     */
    protected HashSet<String> childParserQNames;

    public SaxParser() {

    }

    public SaxParser(HashSet<String> childParserQNames) {
        this.childParserQNames = childParserQNames;
    }

    protected void startElement(String uri, String localName, String qName, Attributes attributes) {
        if(qName == null){
            return;
        }
        if(saxParser != null){
            saxParser.startElement(uri, qName, qName, attributes);

        }else if(childParserQNames != null && childParserQNames.contains(qName)){
            this.saxParser = dispatchTo(qName, attributes);
            if(this.saxParser != null){
                this.saxParserQName = qName;
                saxParser.parserStart(attributes);
            }

        }else{
            curQName = qName;
            if(curValue.length() > 0){
                curValue.delete(0, curValue.length());
            }
        }
    }

    protected void endElement(String uri, String localName, String qName) {
        if(qName == null){
            return;
        }
        if(qName.equals(saxParserQName)){
            if(saxParser != null){
                saxParser.parserEnd();
            }
            saxParser = null;
            saxParserQName = null;

        }else if(saxParser != null){
            saxParser.endElement(uri, qName, qName);

        }else{
            parserElementEnd(qName, curValue.toString());
            curQName = null;
            if(curValue.length() > 0){
                curValue.delete(0, curValue.length());
            }
        }
    }

    protected void characters(char[] ch, int start, int length) {
        if(saxParser != null){
            saxParser.characters(ch, start, length);

        }else{
            String data = new String(ch, start, length);
            if(data.length() > 0 && curQName != null){
                curValue.append(data);
            }
        }
    }


    /**
     * 开始解析一个输入流
     * @param is 文件输入流
     * @param rootParserQName 解析的文件根节点
     * @param rootParser 根解析器
     */
    public static void start(InputStream is,
                             final String rootParserQName,
                             final SaxParser rootParser){
        try {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            parser.parse(is, new DefaultHandler(){
                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    if(qName == null){
                        return;
                    }
                    if(rootParser != null){
                        rootParser.startElement(uri, qName, qName, attributes);

                    }else if(qName.equals(rootParserQName)){
                        rootParser.parserStart(attributes);
                    }
                }

                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {
                    if(rootParser != null){
                        rootParser.characters(ch, start, length);
                    }
                }

                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    if(qName == null){
                        return;
                    }
                    if(qName.contains(rootParserQName)){
                        if(rootParser != null){
                            rootParser.parserEnd();
                        }

                    }else if(rootParser != null){
                        rootParser.endElement(uri, qName, qName);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 节点解析开始
     */
    public abstract void parserStart(Attributes attributes);
    /**
     * 一个子节点解析结束
     * @param value characters获得的值
     */
    public abstract void parserElementEnd(String qName, String value);
    /**
     * 解析事件需要向下传递,返回需要传递的子SaxParser
     */
    public abstract SaxParser dispatchTo(String qName, Attributes attributes);
    /**
     * 节点解析结束
     */
    public abstract void parserEnd();

}

 

需要解析的xml文件test.xml:

<?xml version="1.0" encoding="UTF-8"?>

<kml xmlns:gx="http://www.google.com/kml/ext/2.2">

  <Document id="123">
    <description>abc</description>
    <author>csq</author>
    <ExtendedData>
      <Data name="TrackId">
        <value>293156</value>
      </Data>
      <Data name="TrackTypeId">
        <value>8</value>
      </Data>
    </ExtendedData>

    <Placemark>
      <name>深圳湾公园</name>
      <TimeStamp>
        <when>2015-03-21T10:00:13Z</when>
      </TimeStamp>
      <Point>
        <coordinates>113.93946,22.48955,9.0</coordinates>
      </Point>
    </Placemark>

  </Document>

</kml>

   

开始解析:

根节点kml,根节点解析器KmlParser

SaxParser.start(getAssets().open("test.kml"), "kml", new Kml.KmlParser(kml));

 

部分节点解析实现:

public static class KmlParser extends SaxParser {

        private Kml kml;

        public KmlParser(Kml kml) {
            super(new HashSet<String>());
            this.kml = kml;
            childParserQNames.add("Document");
        }

        @Override
        public void parserStart(Attributes attributes) {

        }

        @Override
        public void parserElementEnd(String qName, String value) {

        }

        @Override
        public SaxParser dispatchTo(String qName, Attributes attributes) {
            if(qName.equals("Document")){
                return new Document.DocumentParser(kml);
            }
            return null;
        }

        @Override
        public void parserEnd() {

        }

    }

  

public static class DocumentParser extends SaxParser {
        private Kml kml;
        private Document document;

        public DocumentParser(Kml kml) {
            super(new HashSet<String>());
            this.kml = kml;
            childParserQNames.add("ExtendedData");
            childParserQNames.add("Placemark");
        }

        @Override
        public void parserStart(Attributes attributes) {
            document = new Document();
            document.id = attributes.getValue("id");
        }

        @Override
        public void parserElementEnd(String qName, String value) {
            if(document == null){
                return;
            }
            if(qName.equals("description")){
                document.description = value;

            }else if(qName.equals("author")){
                document.author = value;
            }
        }

        @Override
        public SaxParser dispatchTo(String qName, Attributes attributes) {
            if(document == null){
                return null;
            }
            if(qName.equals("ExtendedData")){
                return new ExtendedData.ExtendedDataParser(document);

            }else if(qName.equals("Placemark")){
                return new Placemark.PlacemarkParser(document);
            }
            return null;
        }

        @Override
        public void parserEnd() {
            kml.document = document;
        }
    }

  

public static class PlacemarkParser extends SaxParser {

        private Document document;
        private Placemark placemark;

        public PlacemarkParser(Document document) {
            super(new HashSet<String>(1));
            childParserQNames.add("Point");
            this.document = document;
        }

        @Override
        public void parserStart(Attributes attributes) {
            placemark = new Placemark();
        }

        @Override
        public void parserElementEnd(String qName, String value) {
            if(qName.equals("name")){
                placemark.name = value;

            }else if(qName.equals("when")){
                placemark.when = value;
            }
        }

        @Override
        public SaxParser dispatchTo(String qName, Attributes attributes) {
            if(qName.equals("Point")){
                return new Point.PointParser(placemark);
            }
            return null;
        }

        @Override
        public void parserEnd() {
            document.placemark = placemark;
        }
    }

  

public static class ExtendedDataParser extends SaxParser {

        private Document document;
        private ExtendedData extendedData;

        public ExtendedDataParser(Document document) {
            super(new HashSet<String>(1));
            childParserQNames.add("Data");
            this.document = document;
        }

        @Override
        public void parserStart(Attributes attributes) {
            extendedData = new ExtendedData();
        }

        @Override
        public void parserElementEnd(String qName, String value) {

        }

        @Override
        public SaxParser dispatchTo(String qName, Attributes attributes) {
            if(qName.equals("Data")){
                return new Data.DataParser(extendedData);
            }
            return null;
        }

        @Override
        public void parserEnd() {
            document.extendedDatas = extendedData;
        }
    }

  

......

 

解析结果: