zoukankan      html  css  js  c++  java
  • Android XML数据解析

    XML:可扩展标记语言。一般用于数据存储,SharedPreference就是使用xml文件保存信息的,SQLite底层也是xml文件,在网络方面通常作为信息的载体,把数据包装成xml来传递。

    XML解析方式:SAX、DOM、PULL。

    SAX解析XML数据

      SAX解析速度快,占用内存少,非常适合Android等移动设备。SAX解析采用的是事件驱动,不需要解析整个文档,而是在解析过程中,判断读到的字符是否符合xml语法的某个部分(文档开始、结束,标签开始、结束),符合则出触发事件(回调方法),这些方法定义在ContentHandler接口中,为便于使用Android提供了一个DefaultHandler帮助类,只要继承这个类,重写相应的方法即可。

      重写的方法:

        startDocument():文档开始时触发,做初始化工作。

        endDocument():文档结束时触发,完成善后工作。

        startElement():元素开始时触发。

        endElement():元素结束时触发。  

        characters(ch,start,length):处理在xml中读到的内容,ch存放文件内容、start和length读到内容在数组中的起始位置和长度。使用new String(ch,start,length)可以获取内容。

      核心代码

    public class SaxHelper extends DefaultHandler {
        private Person person;
        private ArrayList<Person> persons;
    
        //当前解析的元素标签
        private String tagName = null;
    
        /**
         * 当读取到文档开始标志是触发,通常在这里完成一些初始化操作
         * @throws SAXException
         */
        @Override
        public void startDocument() throws SAXException {
            this.persons = new ArrayList<Person>();
            Log.i("SAX", "读取到文档头,开始解析xml");
    
        }
    
        /**
         * 读到一个开始标签时调用,第二个参数为标签名,最后一个参数为属性数组
         * @param uri
         * @param localName
         * @param qName
         * @param attributes
         * @throws SAXException
         */
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws   SAXException {
            if (localName.equals("person")){
                person = new Person();
                person.setId(Integer.parseInt(attributes.getValue("id")));
                Log.i("SAX", "开始处理person元素~");
    
            }
            this.tagName = localName;
    
        }
    
        /**
         * 读到到内容,第一个参数为字符串内容,后面依次为起始位置与长度
         * @param ch
         * @param start
         * @param length
         * @throws SAXException
         */
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            //判断当前标签是否有效
            if (this.tagName != null){
                String data = new String(ch, start, length);
    
                //读取标签中的内容
                if (this.tagName.equals("name")){
                    this.person.setName(data);
                    Log.i("SAX", "处理name元素内容");
    
                }else if (this.tagName.equals("age")){
                    this.person.setAge(Integer.parseInt(data));
                    Log.i("SAX", "处理age元素内容");
    
                }
    
            }
    
        }
    
        /**
         * 处理元素结束时触发,这里将对象添加到结合中
         * @param uri
         * @param localName
         * @param qName
         * @throws SAXException
         */
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (localName.equals("person")){
                this.persons.add(person);
                person = null;
                Log.i("SAX", "处理person元素结束~");
    
            }
            this.tagName = null;
    
        }
    
        /**
         * 读取到文档结尾时触发,
         * @throws SAXException
         */
        @Override
        public void endDocument() throws SAXException {
            super.endDocument();
            Log.i("SAX", "读取到文档尾,xml解析结束");
        }
    
        //获取persons集合
        public ArrayList<Person> getPersons(){
            return  persons;
        }
    
    }

    在MainActivity.java中写上这样一个方法,然后要解析XML的时候调用下

    private ArrayList<Person> readxmlForSAX() throws Exception { 
    
          //获取文件资源建立输入流对象
          InputStream is = getAssets().open("person1.xml");
    
         //①创建XML解析处理器 
          SaxHelper ss = new SaxHelper(); 
    
          //②得到SAX解析工厂 
          SAXParserFactory factory = SAXParserFactory.newInstance();
    
          //③创建SAX解析器 
          SAXParser parser = factory.newSAXParser(); 
    
          //④将xml解析处理器分配给解析器,对文档进行解析,将事件发送给处理器 
              parser.parse(is, ss);
    
             is.close();
             return ss.getPersons();
    }

    DOM解析XML数据

      DOM解析xml文件时,会将文件中所有内容以文档树的形式存放到内存中,然后使用DOM API遍历、检索数据。DOM解析比较直观,编码较为简单,但是内存消耗大。

      DOM中的api:

        DocumentBuilderFactory()(解析工厂类):创建:DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();

        DocumentBuilder(解析器类):通过解析工厂来获得:DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();

        Document(文档树模型):将要解析的xml文件读入DOM解析器Document doc = dbBuilder.parse(context.getAssets().open("person2.xml"));

        NodeList(结点列表类):含有方法:item(index)、getLength()

        Node()(结点类):DOM中最基本的对象,抽象结点,一般使用它的子对象,Element、Attr、Text等

        Element()(元素类):方法:getAttribute()、getTagName()

        Attr()(属性类):某个元素的属性。

      核心代码

    public class DomHelper {
        public static ArrayList<Person> queryXML(Context mContent){
    
        ArrayList<Person> persons = new ArrayList<Person>();
    
        try {
            //①获得DOM解析器的工厂示例:
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    
            //②从Dom工厂中获得dom解析器
            DocumentBuilder builder = dbFactory.newDocumentBuilder();
    
            //③把要解析的xml文件读入Dom解析器
            Document document = builder.parse(mContent.getAssets().open("person2.xml"));
            System.out.println("处理该文档的DomImplemention对象=" + document.getImplementation());
    
            //④得到文档中名称为person的元素的结点列表
            NodeList nodeList = document.getElementsByTagName("person");
    
            //⑤遍历该集合,显示集合中的元素以及子元素的名字
            for (int i = 0; i < nodeList.getLength(); i ++){
                //先从Person元素开始解析
                Element personElement = (Element)nodeList.item(i);
                Person person = new Person();
                person.setId(Integer.valueOf(personElement.getAttribute("id")));
    
                //获取person下的name和age的Note集合
                NodeList childList = personElement.getChildNodes();
                for (int j = 0; j < childList.getLength(); j ++){
    
                    Node childNode = childList.item(j);
    
                    //判断子note类型是否为元素Note
                    if (childNode.getNodeType() == Node.ELEMENT_NODE){
    
                        Element childElement = (Element)childNode;
    
                        if ("name".equals(childElement.getNodeName())){
                            person.setName(childElement.getFirstChild().getNodeValue());
    
                        }else if("age".equals(childElement.getNodeName())){
                            person.setAge(Integer.valueOf(childElement.getFirstChild().getNodeValue()));
    
                        }
    
                    }
    
                }
                persons.add(person);
    
            }
    
        } catch (Exception e) {
            e.printStackTrace();
        }
        return persons;
    
    }

    PULL解析XML数据

      Android中内置了PULL解析器,PULL解析同样采用事件驱动,编码简单,只需处理开始和结束事件,通常使用switch语句,根据事件的类型,匹配不同的处理方法。

      事件类型:START_DOCUMENT、START_TAG、TEXT、END_TAG、END_DOCUMENT。

      PULL解析返回的是数字,需要我们自己获取产生的事件,然后做相应的操作。

      PULL解析xml文件流程: 

    public static ArrayList<Person> getPersons(InputStream xml) throws Exception{
      ArrayList<Person> persons = null;
      Person person = null;
      //
    1、创建一个xml解析的工厂 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); //2、获得xml解析类的引用 XmlPullParser parser = factory.newPullParser(); parser.setInput(xml, "UTF-8"); //3、获得事件的类型 int eventType = parser.getEventType();
      //4、用switch对不同的事件进行不同的处理
    while (eventType != XmlPullParser.END_DOCUMENT){ switch (eventType){ case XmlPullParser.START_DOCUMENT:{ persons = new ArrayList<Person>(); break; } case XmlPullParser.START_TAG:{ if ("person".equals(parser.getName())){ person = new Person(); // 取出属性值 int id = Integer.parseInt(parser.getAttributeValue(0)); person.setId(id); }else if("name".equals(parser.getName())){ // 获取该节点的内容 String name = parser.nextText(); person.setName(name); }else if("age".equals(parser.getName())){ int age = Integer.parseInt(parser.nextText()); person.setAge(age); } break; } case XmlPullParser.END_TAG:{ if ("person".equals(parser.getName())){ persons.add(person); person = null; } break; } } eventType = parser.next(); } return persons; }

     PULL生成xml文件流程

    public static void save(List<Person> persons, OutputStream outputStream) throws Exception{
      //创建XmlSerializer实例 XmlSerializer serializer
    = Xml.newSerializer();
      //为XmlSerializer设置输入流和编码格式 serializer.setOutput(outputStream,
    "UTF-8");
      //设置xml的编码格式 serializer.startDocument(
    "UTF-8", true);
      //设置根元素 serializer.startTag(
    null, "persons");
      //遍历元素依次写入标签和属性
    for (Person person: persons) { serializer.startTag(null, "person"); serializer.attribute(null, "id", person.getId() + ""); serializer.startTag(null, "name"); serializer.text(person.getName()); serializer.endTag(null, "name"); serializer.startTag(null, "age"); serializer.text(person.getAge() + ""); serializer.endTag(null, "age");
        //设置完结元素标签 serializer.endTag(
    null, "person"); } serializer.endTag(null, "persons");
      //结束文档 serializer.endDocument();
      //flush()刷新,将数据写入文件,关闭输出流 outputStream.flush(); outputStream.close(); }

    参考文献:http://www.jianshu.com/p/2fe796ca638c                        

        

  • 相关阅读:
    Codeforces Round #461 (Div. 2)B-Magic Forest+位运算或优雅的暴力
    动态规划:树形DP
    动态规划:划分DP
    动态规划:状压DP
    图论:树的直径
    图论:点分治
    图论:2-SAT
    数据结构&图论:K短路-可持久化可并堆
    图论:次短路
    图论:曼哈顿距离最小生成树
  • 原文地址:https://www.cnblogs.com/yl-saber/p/7447511.html
Copyright © 2011-2022 走看看