Andorid XML三种解析方式和优缺点

2020-06-09  本文已影响0人  梦星夜雨

前言

Andorid XML有SAX, DOM, Pull三种解析方式。本文以下面的xml为例。
<?xml version="1.0" encoding="UTF-8"?>

<?xml version="1.0" encoding="UTF-8"?>
<students>
    <student>
        <name>张三</name>
        <studentId>12</studentId>
        <score>67</score>
    </student>
    <student>
        <name>李四</name>
        <studentId>13</studentId>
        <score>79</score>
    </student>
    <student>
        <name>王五</name>
        <studentId>14</studentId>
        <score>92</score>
    </student>
</students>

1.SAX解析

SAX(Simple API for XML)解析器是一种基于事件的解析器,从文件的开始顺序解析到文档的结束,不可暂停或倒退。

新建XMLContentHandler类继承DefaultHandler,重写startDocument,startElement,characters,endElement方法。只需要传入InputStream即可,代码如下:

package com.xml.test;

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

import java.util.ArrayList;
import java.util.List;

public class XMLContentHandlerStudent extends DefaultHandler {

    private List<Student> students = null;
    private Student currentStudent;
    private String tagName = null;//当前解析的元素标签

 public static List<Student> readXmlBySAX(InputStream inputStream) {
        try {
            /**【创建解析器】**/
            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser saxParser = spf.newSAXParser();
            XMLContentHandlerStudent handler = new XMLContentHandlerStudent();
            saxParser.parse(inputStream, handler);
            inputStream.close();
            return handler.getStudents();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<Student> getStudents() {
        return students;
    }

    /**文档开始时,调用此方法**/
    @Override
    public void startDocument() throws SAXException {
        students = new ArrayList<>();
    }

    /**
     * 标签开始时,调用此方法
     * uri 命名空间|localName是不带命名空间前缀的标签名|
     * qName 带命名空间前缀的标签名|
     * attributes 可以得到所有的属性名和对应的值
     **/
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (localName.equals("student")) {
            currentStudent = new Student();
//            currentStudent.setId(Integer.parseInt(attributes.getValue("id")));
        }
        this.tagName = localName;
    }

    /**
     * 接收标签中字符数据时,调用此方法
     * ch 存放标签中的内容,
     * start 起始位置,
     * length 内容长度
     **/
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (tagName != null) {
            String data = new String(ch, start, length);
            if (tagName.equals("name")) {
                this.currentStudent.setName(data);
            } else if (tagName.equals("studentId")) {
                this.currentStudent.setStudentId(Short.parseShort(data));
            } else if (tagName.equals("score")) {
                this.currentStudent.setScore(Short.parseShort(data));
            }
        }
    }
    /**
     * 标签结束时,调用此方法
     * localName 表示元素本地名称(不带前缀)
     * qName 表示元素的限定名(带前缀)
     **/
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (localName.equals("student")) {
            students.add(currentStudent);
            currentStudent = null;
        }
        this.tagName = null;
    }
}

2.DOM解析

DOM(Document Object Model)是将其转换为一个对象模型的集合,用树这种数据结构对信息进行储存,通过DOM接口,应用程序可以在任何时候访问xml文档中的任何一部分数据。

public static List<Student> readXmlByDOM(InputStream inputStream){
        List<Student> students = new ArrayList<>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document dom = builder.parse(inputStream);
            Element rootElement = dom.getDocumentElement();
            NodeList items = rootElement.getElementsByTagName("student");
            for (int i = 0; i < items.getLength(); i++) {
                Element elementItem = (Element) items.item(i);
                NodeList childsNodes = elementItem.getChildNodes();
                Student student = new Student();
                for (int j = 0; j < childsNodes.getLength(); j++) {
                    Node node = (Node) childsNodes.item(j);
                    // 判断是否为元素类型
                    if(node.getNodeType() == Node.ELEMENT_NODE){
                        Element childNode = (Element) node;
                        String nodeName = childNode.getNodeName();
                        // 判断对应元素
                        if ("name".equals(childNode.getNodeName())) {
                            student.setName(childNode.getFirstChild().getNodeValue());
                        }else if("studentId".equals(childNode.getNodeName())){
                            student.setStudentId(Integer.parseInt(childNode.getFirstChild().getNodeValue()));
                        } else if ("score".equals(childNode.getNodeName())) {
                            student.setScore(Integer.parseInt(childNode.getFirstChild().getNodeValue()));
                        }
                    }
                }
                students.add(student);
            }
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return students;
    }

3.Pull解析

Pull解析与SAX解析原理上类似,但提供了开始,结束元素,并且提供了NEXT方法主动提取。在移动端而言,Pull解析最优。

public static List<Student> readXmlByPull(InputStream inputStream) {
        XmlPullParser parser = Xml.newPullParser();
        try {
            parser.setInput(inputStream, "UTF-8");
            int eventType = parser.getEventType();

            Student currenStudent = null;
            List<Student> students = null;

            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                    case XmlPullParser.START_DOCUMENT: // 文档开始事件
                        students = new ArrayList<>();
                        break;
                    case XmlPullParser.START_TAG: // 元素(即标签)开始事件
                        String name = parser.getName();
                        if (name.equals("student")) {
                            currenStudent = new Student();
                        } else if (currenStudent != null) {
                            // 判断标签名(元素名)
                            if (name.equals("name")) {
                                currenStudent.setName(parser.nextText());
                            } else if (name.equals("studentId")) {
                                currenStudent.setStudentId(Integer.valueOf(parser.nextText()));
                            } else if (name.equals("score")) {
                                currenStudent.setScore(Integer.valueOf(parser.nextText()));
                            }
                        }
                        break;
                    case XmlPullParser.END_TAG:// 元素结束事件
                        if (parser.getName().equalsIgnoreCase("student") && currenStudent != null) {
                            students.add(currenStudent);
                            currenStudent = null;
                        }
                        break;
                }
                eventType = parser.next();
            }
            inputStream.close();
            return students;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
上一篇下一篇

猜你喜欢

热点阅读