• Android学习(三)Android解析XML


    简介

    在Android中,XML资源存储在assets或者res\xml或者res\raw目录中,我们在Eclipse构建Android项目是,xml及raw目录初始是未创建的,如果我们需要用到原始的xml资源,需要我们自己手动构建文件夹,并存储我们的资源到指定的(这里是raw或者xml)目录中。有了xml资源,我们在应用中就需要解析它,在Android中,常见的解析xml的方式有一下三种:SAX、Pull、Dom解析方式。

    Pull方式解析

    Pull解析采用的是事件驱动的方式来解析XML文档,当我们开始解析后,我们可以通过调用XmlResourceParser.next()解析下一个解析事件(开始文档,结束文档,开始标签,结束标签)。当我们解析到某一个元素是我们可以通过XmlPullParser.getAttributte()方法来获取属性的值,也可调用它的XmlPullParser.nextText()获取本节点的值.

    接下来我们会用一个XML文件并把它解析到一个对象集合中,首先我们需要构建我们要演示的XML文件以及我们的对象类

    如下所示,我们用如下的XML文件来演示三种解析方式

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <customer name="tom" age="20" gender="male" >
            <telphone>
                <phone>13636713128</phone>
            </telphone>
            <email>tom@yahoo.com</email>
        </customer>
        <customer name="kite" age="21" gender="male" >
            <telphone/>
            <email>kite@qq.com</email>
        </customer>
        <customer name="jeriffe" age="28" gender="male" >
            <telphone>
                <phone>13636713128</phone>
                <phone>13892008888</phone>
            </telphone>
           <email>jeriffe@126.com</email>
        </customer>
    </resources>

    XML文件我们分别存储在如下所示的3个目录中:

    image

    如下所示,是我们将要用到的对象类:

    package com.amaker.ch03.xml;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Person {
        private String name;
        private String sex;
        private int age;
        private String email;
        private List<String> phonesList;
    
        public Person() {
            phonesList = new ArrayList<String>();
        }
    
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
        public List<String> getPhonesList() {
            return phonesList;
        }
        public void setPhonesList(List<String> phonesList) {
            this.phonesList = phonesList;
        }
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
        public void addPhone(String phoneNumber) {
            this.phonesList.add(phoneNumber);
        }
        @Override
        public String toString() {
            String phoneString = "";
            for (String phone : phonesList) {
                phoneString += "\n    " + phone;
            }
            return String.format("姓名:%s\n年龄:%d\n性别:%s\nEmail:%s\n电话:%s", name, age,sex, email, phoneString);
        }
    
    }
    

    下面的代码片段是一个用Pull方式解析的示例(文件存储在res\xml目录下)

        private List<Person> parseByXmlPullParser() {
            List<Person> resultsList = new ArrayList<Person>();
            Person person = null;
    
            Resources resources = getResources();
            XmlResourceParser xrParser = resources.getXml(R.xml.customers);
            try {
                while (xrParser.getEventType() != XmlResourceParser.END_DOCUMENT) {
                    if (xrParser.getEventType() == XmlResourceParser.START_TAG) {
                        String name = xrParser.getName();
                        if (name.equals("customer")) {
                            person = new Person();
                            person.setName(xrParser.getAttributeValue(null, "name"));
                            person.setAge(Integer.parseInt(xrParser
                                    .getAttributeValue(1)));
                            person.setSex(xrParser.getAttributeValue(2));
    
                        } else if (name.equals("phone")) {
                            person.addPhone(xrParser.nextText());
                        } else if (name.equals("email")) {
                            xrParser.next();
                            person.setEmail(xrParser.getText());
                        }
                    } else if (xrParser.getEventType() == XmlPullParser.END_TAG) {
                        String name = xrParser.getName();
                        if (name.equals("customer")) {
                            resultsList.add(person);
                        }
                    }
    
                    xrParser.next();
                }
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return resultsList;
        }

    SAX解析

    SAX即是:Simple API for XML。SAX解析也是一种基于事件驱动的API,有两个部分,解析器和事件处理器,解析器就是XMLReader接口,负责读取XML文档和向事件处理器发送事件(也是事件源),事件处理器接口,负责对发送的事件响应和进行XML文档处理。

    事件处理器有4个接口:

    1.EntityResolver
    2.DTDHandler
    3.ContentHandler
    4.ErrorHandler

    解析器通过其setXXX()方法来注册事件处理器,在我们自己的解析中,我们不需要实现上述的事件处理器接口,因为SAX已经为我们提供了一个默认的基类DefaultHandler,我们只需要extend这个接口来实现我们的解析逻辑既可。

    用SAX解析需要如下的几个步骤:

    1:构建SAXParserFactory对象
    2: 构建SAXParser解析器:根据SAXParserFactory.newSAXParser()方法返回一个SAXParser解析器
    3:构建XMLReader:根据SAXParser解析器获取事件源对象XMLReader
    4:构建一个自定义的Handler对象
    5:连接事件源对象XMLReader到事件处理类DefaultHandler中
    6:读取文件流
    7:调用XMLReader的parse方法从输入源中获取到的xml数据
    8:通过我们自定义的Handler返回我们需要的数据集合。

    下面我们来看一个SAX解析的样例

    注:SAX解析的XML文件要存储在res\raw目录中,存储在res\xml目录中运行时报错。

        // Simple API for XML
        private List<Person> parseBySaxParser()
                throws ParserConfigurationException, SAXException, IOException {
            // 1.构建一个工厂SAXParserFactory
            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
            // 2.构建并实例化SAXPraser对象
            SAXParser saxParser = parserFactory.newSAXParser();
            // 3.构建XMLReader解析器
            XMLReader xmlReader = saxParser.getXMLReader();
            // 4.这里是我们的具体类型的Handler对象
            PersonSaxParserHandler parserHandler = new PersonSaxParserHandler();
            // 5.解析器注册一个处理器
            xmlReader.setContentHandler(parserHandler);
            // 6.读取文件流
            InputStream stream = getResources().openRawResource(R.raw.customers);
            InputSource is = new InputSource(stream);
            // 6.解析文件
            xmlReader.parse(is);
    
            List<Person> resList = parserHandler.getPersons();
            return resList;
        }

    我们继承扩展的事件处理器

    package com.amaker.ch03.xml;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.DefaultHandler;
    
    import android.R.integer;
    
    public class PersonSaxParserHandler extends DefaultHandler {
    
        class PersonConst {
            public static final int Persons = 1;
            public static final int Person_TELPHONE = 2;
            public static final int Person_PHONE = 3;
            public static final int Person_EMAIL = 4;
    
        }
        private List<Person> persons = new ArrayList<Person>();
        private Person person = null;
        private int currentState = 0;
    
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            String theString = new String(ch, start, length);
            switch (currentState) {
                case PersonConst.Person_EMAIL :
                    person.setEmail(theString);
                    break;
                case PersonConst.Person_PHONE :
                    person.addPhone(theString);
                    break;
                default :
                    break;
            }
            currentState=0;
        }
        @Override
        public void startDocument() throws SAXException {
            // 文档解析开始
            super.startDocument();
        }
        @Override
        public void endDocument() throws SAXException {
            // 文档解析开始
        }
    
        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
    
            String node = localName.length() != 0 ? localName : qName;
            // 开始解析节点
            if (node.equals("customer")) {
                currentState = PersonConst.Persons;
    
                person = new Person();
                person.setName(attributes.getValue("name"));
                person.setAge(Integer.parseInt(attributes.getValue("age")));
                person.setSex(attributes.getValue("gender"));
    
                return;
            }
            
            if (node.equals("phone")) {
                currentState = PersonConst.Person_PHONE;
                return;
            }
            if (node.equals("email")) {
                currentState = PersonConst.Person_EMAIL;
                return;
            }
            
            currentState=0;
        }
    
        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            // 解析节点结束
            if (localName.equals("customer")) {
                persons.add(person);
                return;
            }
        }
    
        public List<Person> getPersons() {
            return persons;
        }
    }
    

    DOM解析

    DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据的,但是这样一来,如果xml文件很大呢?手机CPU处理能力当然不能与PC机器比,因此在处理性能上会有折损。所以如果XML文件比较大,建议还是用上述的方式,而不用DOM方式。

    DOM解析的步骤一般如下:

    1.构建一个DocumentBuilderFactory实例
    2.构建DocumentBuilder
    3.加载XML文档(Document)
    4.遍历XML文档

    下来我们来看DOM解析的一个示例(文件存储在assets目录下)

        private List<Person> parseByDomParser()
                throws ParserConfigurationException, SAXException, IOException {
            List<Person> resList = new ArrayList<Person>();
    
            // 构建一个DocumentBuilderFactory实例
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 构建DocumentBuilder
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 读取文件流
           AssetManager assetManager=getAssets();
            InputStream stream=assetManager.open("customers.xml");
            //InputStream stream = getResources().openRawResource(R.raw.customers);
            // 得到代表整个xml的Document对象
            Document document = builder.parse(stream);
    
            // 遍历所有节点
            Element root = document.getDocumentElement();
            // 获取根节点的所有customer的节点
            NodeList nodes = root.getElementsByTagName("customer");
    
            for (int index = 0; index < nodes.getLength(); index++) {
                Person person = new Person();
                // 获取person元素节点
                Element personElement = (Element) (nodes.item(index));
                // 获取person中属性(Attributes)值
                person.setName(personElement.getAttribute("name"));
                person.setAge(Integer.parseInt(personElement.getAttribute("age")));
                person.setSex(personElement.getAttribute("gender"));
    
                // 获取telphone下标签
                Element telphoneElement = (Element) personElement
                        .getElementsByTagName("telphone").item(0);
                NodeList phoneNodes = telphoneElement.getElementsByTagName("phone");
                for (int pIndex = 0; pIndex < phoneNodes.getLength(); pIndex++) {
                    // 获取phone元素节点
                    Element phoneElement = (Element) (phoneNodes.item(pIndex));
                    person.addPhone(phoneElement.getFirstChild().getNodeValue());
                }
                // 获取email下标签
                Element emailElement = (Element) personElement
                        .getElementsByTagName("email").item(0);
                person.setEmail(emailElement.getFirstChild().getNodeValue());
    
                resList.add(person);
            }
            return resList;
        }
    

    下面就是我们的Activity类及运行效果图

    public class TestXmlActivity extends Activity implements View.OnClickListener {
        private TextView myTextView;
        private Button pullButton, saxButton, domButton;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.test_xml);
    
            setupViews();
        }
    
        private void setupViews() {
            myTextView = (TextView) findViewById(R.id.xmlContentTextView01);
    
            pullButton = (Button) findViewById(R.id.xmltTestButton01);
            pullButton.setOnClickListener(this);
    
            saxButton = (Button) findViewById(R.id.xmltTestButton02);
            saxButton.setOnClickListener(this);
    
            domButton = (Button) findViewById(R.id.xmltTestButton03);
            domButton.setOnClickListener(this);
        }
    
        public void onClick(View v) {
            StringBuilder sb = new StringBuilder();
            List<Person> resultsList = new ArrayList<Person>();
            try {
                switch (v.getId()) {
                    case R.id.xmltTestButton01 :
                        resultsList = parseByXmlPullParser();
                        sb.append("使用Pull方式解析XML\n");
                        break;
                    case R.id.xmltTestButton02 :
                        resultsList = parseBySaxParser();
                        sb.append("使用SAX方式解析XML\n");
                        break;
                    case R.id.xmltTestButton03 :
                        resultsList = parseByDomParser();
                        sb.append("使用DOM方式解析XML\n");
                        break;
                    default :
                        break;
                }
            } catch (ParserConfigurationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SAXException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            for (Person person : resultsList) {
                sb.append("*************************************************\n");
                sb.append(person.toString());
                sb.append("\n");
            }
    
            myTextView.setText(sb.toString());
        }
    }

    imageimageimage

    Activity的Layout文件比较简单,3个Button及一个TextView控件,这里就不贴其代码了。

    结束语

    以上我们介绍了在Android下常用的3种解析XML文件的方式,我们也分别演示了从res\xml、res\raw、及assets目录下获取XML文件,如果想深入了解这3中方式,可以查看相关的SDK文档。

  • 相关阅读:
    Java学习笔记21---内部类之对成员内部类的补充说明(二)(修正)
    Java学习笔记20---内部类之对成员内部类的补充说明(一)
    Java学习笔记19---内部类之简介成员内部类、局部内部类及匿名内部类
    Java学习笔记18---final关键字修饰变量、方法及类
    Java学习笔记17---成员方法的重载与重写
    Java学习笔记16---抽象类与接口的浅显理解
    Java学习笔记15---instanceof与向下转型
    把大端、小端与堆、栈的生长方向联系起来记忆
    2020综合实践—第7次实践作业 03组
    2020综合实践 第6次实践作业 03组
  • 原文地址:https://www.cnblogs.com/jeriffe/p/2772802.html
Copyright © 2020-2023  润新知