Android中XML解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中XML解析相关的知识,希望对你有一定的参考价值。

package com.example.thebroadproject;

public class Book {  
    private int id;  
    private String name;  
    private float price;  
      
    public int getId() {  
        return id;  
    }  
  
    public void setId(int id) {  
        this.id = id;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public float getPrice() {  
        return price;  
    }  
  
    public void setPrice(float price) {  
        this.price = price;  
    }  
    
    public void addPrice(){
        price=price+1;
    }
  
    @Override  
    public String toString() {  
        return "id:" + id + ", name:" + name + ", price:" + price;  
    }  
}  

 

第一种:DOM。

DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。

package com.example.thebroadproject;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class DomBookParser {

    public List<Book> parse(InputStream is) throws Exception {
        List<Book> books = new ArrayList<Book>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 取得DocumentBuilderFactory实例
        DocumentBuilder builder = factory.newDocumentBuilder(); // 从factory获取DocumentBuilder实例
        Document doc = builder.parse(is); // 解析输入流 得到Document实例
        Element rootElement = doc.getDocumentElement();
        NodeList items = rootElement.getElementsByTagName("book");
        for (int i = 0; i < items.getLength(); i++) {
            Book book = new Book();
            Node item = items.item(i);
            NodeList properties = item.getChildNodes();
            for (int j = 0; j < properties.getLength(); j++) {
                Node property = properties.item(j);
                String nodeName = property.getNodeName();
                if (nodeName.equals("id")) {
                    book.setId(Integer.parseInt(property.getFirstChild().getNodeValue()));
                } else if (nodeName.equals("name")) {
                    book.setName(property.getFirstChild().getNodeValue());
                } else if (nodeName.equals("price")) {
                    book.setPrice(Float.parseFloat(property.getFirstChild().getNodeValue()));
                }
            }
            books.add(book);
        }
        return books;
    }

    public String serialize(List<Book> books) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.newDocument(); // 由builder创建新文档

        Element rootElement = doc.createElement("books");

        for (Book book : books) {
            Element bookElement = doc.createElement("book");
            bookElement.setAttribute("id", book.getId() + "");

            Element nameElement = doc.createElement("name");
            nameElement.setTextContent(book.getName());
            bookElement.appendChild(nameElement);

            Element priceElement = doc.createElement("price");
            priceElement.setTextContent(book.getPrice() + "");
            bookElement.appendChild(priceElement);

            rootElement.appendChild(bookElement);
        }

        doc.appendChild(rootElement);

        TransformerFactory transFactory = TransformerFactory.newInstance();// 取得TransformerFactory实例
        Transformer transformer = transFactory.newTransformer(); // 从transFactory获取Transformer实例
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // 设置输出采用的编码方式
        transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // 是否自动添加额外的空白
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); // 是否忽略XML声明

        StringWriter writer = new StringWriter();

        Source source = new DOMSource(doc); // 表明文档来源是doc
        Result result = new StreamResult(writer);// 表明目标结果为writer
        transformer.transform(source, result); // 开始转换

        return writer.toString();
    }

}

 

第二种:SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

 

package com.example.thebroadproject;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

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

public class SaxBookParser {

    public List<Book> parse(InputStream is) throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance(); // 取得SAXParserFactory实例
        SAXParser parser = factory.newSAXParser(); // 从factory获取SAXParser实例
        MyHandler handler = new MyHandler(); // 实例化自定义Handler
        parser.parse(is, handler); // 根据自定义Handler规则解析输入流
        return handler.getBooks();
    }

    public String serialize(List<Book> books) throws Exception {
        SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();// 取得SAXTransformerFactory实例
        TransformerHandler handler = factory.newTransformerHandler(); // 从factory获取TransformerHandler实例
        Transformer transformer = handler.getTransformer(); // 从handler获取Transformer实例
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // 设置输出采用的编码方式
        transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // 是否自动添加额外的空白
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); // 是否忽略XML声明

        StringWriter writer = new StringWriter();
        Result result = new StreamResult(writer);
        handler.setResult(result);

        String uri = ""; // 代表命名空间的URI 当URI无值时 须置为空字符串
        String localName = ""; // 命名空间的本地名称(不包含前缀) 当没有进行命名空间处理时 须置为空字符串

        handler.startDocument();
        handler.startElement(uri, localName, "books", null);

        AttributesImpl attrs = new AttributesImpl(); // 负责存放元素的属性信息
        char[] ch = null;
        for (Book book : books) {
            attrs.clear(); // 清空属性列表
            attrs.addAttribute(uri, localName, "id", "string", String.valueOf(book.getId()));// 添加一个名为id的属性(type影响不大,这里设为string)
            handler.startElement(uri, localName, "book", attrs); // 开始一个book元素 关联上面设定的id属性

            handler.startElement(uri, localName, "name", null); // 开始一个name元素 没有属性
            ch = String.valueOf(book.getName()).toCharArray();
            handler.characters(ch, 0, ch.length); // 设置name元素的文本节点
            handler.endElement(uri, localName, "name");

            handler.startElement(uri, localName, "price", null);// 开始一个price元素 没有属性
            ch = String.valueOf(book.getPrice()).toCharArray();
            handler.characters(ch, 0, ch.length); // 设置price元素的文本节点
            handler.endElement(uri, localName, "price");

            handler.endElement(uri, localName, "book");
        }
        handler.endElement(uri, localName, "books");
        handler.endDocument();

        return writer.toString();
    }

    // 需要重写DefaultHandler的方法
    private class MyHandler extends DefaultHandler {

        private List<Book> books;
        private Book book;
        private StringBuilder builder;

        // 返回解析后得到的Book对象集合
        public List<Book> getBooks() {
            return books;
        }

        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
            books = new ArrayList<Book>();
            builder = new StringBuilder();
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            super.startElement(uri, localName, qName, attributes);
            if (localName.equals("book")) {
                book = new Book();
            }
            builder.setLength(0); // 将字符长度设置为0 以便重新开始读取元素内的字符节点
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            super.characters(ch, start, length);
            builder.append(ch, start, length); // 将读取的字符数组追加到builder中
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
            if (localName.equals("id")) {
                book.setId(Integer.parseInt(builder.toString()));
            } else if (localName.equals("name")) {
                book.setName(builder.toString());
            } else if (localName.equals("price")) {
                book.setPrice(Float.parseFloat(builder.toString()));
            } else if (localName.equals("book")) {
                books.add(book);
            }
        }
    }
}

 

第三种 PULL解析XML是在android中用到的比较多,而且Android已经将PULL技术集成到了系统中,所以在使用PULL的时候不需要额外的引入到jar,Android中要是使用上述的四种方式,需要引入额外的jar,当然JavaEE中使用PULL技术进行解析的话,就需要引入PULL所需的jar了,其实PULL技术和SAX技术差不多,Pull解析器和SAX解析器虽有区别但也有相似性。他们的区别为:SAX解析器的工作方式是自动将事件推入注册的事件处理器进行处理,因此你不能控制事件的处理主动结束;而Pull解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析。这是他们主要的区别。
而他们的相似性在运行方式上,Pull解析器也提供了类似SAX的事件,开始文档START_DOCUMENT和结束文档END_DOCUMENT,开始元素START_TAG和结束元素END_TAG,遇到元素内容TEXT等,但需要调用next() 方法提取它们(主动提取事件)。
Android系统中和Pull方式相关的包为org.xmlpull.v1,在这个包中提供了Pull解析器的工厂类XmlPullParserFactory和Pull解析器XmlPullParser,XmlPullParserFactory实例调用newPullParser方法创建XmlPullParser解析器实例,接着XmlPullParser实例就可以调用getEventType()和next()等方法依次主动提取事件,并根据提取的事件类型进行相应的逻辑处理。

 

package com.example.thebroadproject;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import android.util.Xml;

public class PullBookParser {

    public List<Book> parse(InputStream is) throws Exception {
        List<Book> books = null;
        Book book = null;

        XmlPullParser parser = Xml.newPullParser(); // 由android.util.Xml创建一个XmlPullParser实例
        parser.setInput(is, "UTF-8"); // 设置输入流 并指明编码方式

        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            switch (eventType) {
            case XmlPullParser.START_DOCUMENT:
                books = new ArrayList<Book>();
                break;
            case XmlPullParser.START_TAG:
                if (parser.getName().equals("book")) {
                    book = new Book();
                } else if (parser.getName().equals("id")) {
                    eventType = parser.next();
                    book.setId(Integer.parseInt(parser.getText()));
                } else if (parser.getName().equals("name")) {
                    eventType = parser.next();
                    book.setName(parser.getText());
                } else if (parser.getName().equals("price")) {
                    eventType = parser.next();
                    book.setPrice(Float.parseFloat(parser.getText()));
                }
                break;
            case XmlPullParser.END_TAG:
                if (parser.getName().equals("book")) {
                    books.add(book);
                    book = null;
                }
                break;
            }
            eventType = parser.next();
        }
        return books;
    }

    public String serialize(List<Book> books) throws Exception {
        XmlSerializer serializer = Xml.newSerializer(); // 由android.util.Xml创建一个XmlSerializer实例
        StringWriter writer = new StringWriter();
        serializer.setOutput(writer); // 设置输出方向为writer
        serializer.startDocument("UTF-8", true);
        serializer.startTag("", "books");
        for (Book book : books) {
            serializer.startTag("", "book");
            serializer.attribute("", "id", book.getId() + "");

            serializer.startTag("", "name");
            serializer.text(book.getName());
            serializer.endTag("", "name");

            serializer.startTag("", "price");
            serializer.text(book.getPrice() + "");
            serializer.endTag("", "price");

            serializer.endTag("", "book");
        }
        serializer.endTag("", "books");
        serializer.endDocument();

        return writer.toString();
    }
}

 

以上是关于Android中XML解析的主要内容,如果未能解决你的问题,请参考以下文章

Android之DOM解析XML

从流输入中解析没有根元素的 XML 片段列表

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段

无法解析片段中的 findViewById [重复]

Android XML布局中,怎么设置两个Button按钮在同一行显示

Android 之XML数据解析—— SAX解析