欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android数据解析之XML数据解析

程序员文章站 2022-06-16 15:44:32
...

Android数据解析之XML数据解析

在Android中有两种XML,JSON数据形式,XML数据解析有三种,DOM,SAX,PULL;JSON数据解析有JSON,GSON,FastJson.此篇文章解析XML解析。下一篇讲解JSON解析。

概述

定义:
XML(Extensible Markup Language的缩写,意为可扩展的标记语言),它是一种元标记语言,即定义了用于定义其他特定领域有关语义的、结构化的标记语言,这些标记语言将文档分成许多部件并对这些部件加以标识。
XML 文档定义方式有:文档类型定义(DTD)和XML Schema。
DTD定义了文档的整体结构以及文档的语法,应用广泛并有丰富工具支持。
XML Schema用于定义管理信息等更强大、更丰富的特征。XML能够更精确地声明内容,方便跨越多种平台的更有意义的搜索结果。它提供了一种描述结构数据的格式,简化了网络中数据交换和表示,使得代码、数据和表示分离,并作为数据交换的标准格式,因此它常被称为智能数据文档。
由于XML具有很强的扩展性,致使它需要很强的基础规则来支持扩展,所以在编写XML文件时,我们应该严格遵守XML的语法规则,一般XML语法有如下规则
(1)起始和结束的标签相匹配;
(2)嵌套标签不能相互嵌套;
(3)区分大小写。

Android中解析XML数据的三种方式 :
DOM解析:文档对象模型(Document Object Model)将xml文件全部载入,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件。
SAX解析(Simple API for XML):事件驱动,解析速度快,占用内存少。
PULL解析:事件驱动, 在解析过程中, 我们需要自己获取产生的事件然后做相应的操作. Android系统内部在解析各种XML时是用PULL解析器。

XML数据解析方法分析

测试使用的XML数据:

<?xml version="1.0" encoding="utf-8"?>
<books>
    <book>
        <id>1001</id>
        <name>Thinking In Java</name>
        <price>80.00</price>
    </book>
    <book>
        <id>1002</id>
        <name>Core Java</name>
        <price>90.00</price>
    </book>
    <book>
        <id>1003</id>
        <name>Hello, Andriod</name>
        <price>100.00</price>
    </book>
</books>

DOM解析

定义
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。
工作原理
DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档——这就是DOM的工作原理。DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。
常用方法

接口或类名称 接口或类说明
Document 该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。
Element 该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法
Node 该接口提供处理并获取节点和子节点值的方法
NodeList 提供获得子节点个数和当前节点的方法。这样就可以迭代地访问各个节点

编程步骤
DOM解析XML的编程步骤:
1、创建文档对象工厂实例;
2、调用DocumentBuilderFactory中的newDocumentBuilder()方法创建文档对象构造器;
3、将文件流解析成XML文档对象;
4、使用mDocument文档对象得到文档根节点;
5、根据名称获取根节点中的子节点列表;
6 、获取子节点列表中需要读取的节点信息。
源码
Activity中调用

/*
    DOM解析
     */
    public void dom(View view) throws IOException {
        InputStream is = getAssets().open("books.xml");
        parseXMLWithDOM(is);
    }

解析操作:

/*
    DOM解析的操作
     */
    private void parseXMLWithDOM(InputStream xmlData) {
        String id = "";
        String name = "";
        String price = "";
        //创建解析器工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            //创建解析器
            DocumentBuilder builder = factory.newDocumentBuilder();
            //获得Document对象
            Document document = builder.parse(xmlData);//流数据
//    Document document = builder.parse(new InputSource(new StringReader(xmlData)));//字符串数据
            NodeList bookList = document.getElementsByTagName("book");
            for (int i = 0; i < bookList.getLength(); i++) {
                //获得子节点的List
                Node node_bookList = bookList.item(i);
                //获得子节点List里面的节点
                NodeList childNodes = node_bookList.getChildNodes();
                for (int j = 0; j < childNodes.getLength(); j++) {
                    Node childNode = childNodes.item(j);
                    //判断是name还是nickName
                    if ("id".equals(childNode.getNodeName())) {
                        id = childNode.getTextContent();
                    } else if ("name".equals(childNode.getNodeName())) {
                        name = childNode.getTextContent();
                    } else if ("price".equals(childNode.getNodeName())) {
                        price = childNode.getTextContent();
                    }

                }
                Log.e("TAG", "DOM解析的子节点数据:" + "\n" +
                        "id :" + id + "\n" +
                        "name : " + name + "\n" +
                        "price : " + price);
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

测试结果
Android数据解析之XML数据解析

SAX解析

定义
SAX(Simple For XML)是一种基于事件的解析器,它的核心是事件处理模式,它主要是围绕事件源和事件处理器来工作的。当事件源产生事件后,会调用事件处理器中相应的方法来处理一个事件,那在事件源调用对应的方法时也会向对应的事件传递一些状态信息,以便我们根据其状态信息来决定自己的行为。
工作原理
SAX解析工作的主要原理:在读取XML文档内容时,事件源顺序地对文档进行扫描,当扫描到文档的开始与结束(Document)标签、节点元素的开始与结束(Element)标签时,直接调用对应的方法,并将状态信息以参数的形式传递到方法中,然后我们可以依据状态信息来执行相关的自定义操作。
常用方法
首先介绍一个类:DefaultHandler,该类是XML解析接口(EntityResolver, DTDHandler, ContentHandler, ErrorHandler)的缺省实现,在通常情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现这些接口更容易。接着重写startDocument(),startElement(),characters(),endElement和endDocument()五个方法,这些方法会在事件源(在org.xml.sax包中的XMLReader,通过parser()产生事件)读取到不同的XML标签所产生事件时调用。那我们开发时只要在这些方法中实现我们的自定义操作即可

方法名称 方法说明
startDocument() 用于处理文档解析开始时间
startElement(String uri, String localName, String qName, Attributes attributes) 处理元素开始时间,从参数中可以获取元素所在空间的URL,元素名称,属性列表等信息
characters(char[] ch, int start, int length 处理元素的字符内容,从参数中可以获得内容
endElement(String uri, String localName, String qName) 处理元素结束时间,从参数中可以获取元素所在空间的URL,元素名称等信息。
endDocument() 用于处理文档解析的结束事件

编程步骤
SAX解析XML的编程步骤:
1、获取创建一个SAX解析工厂实例;
2、调用工厂实例中的newSAXParser()方法创建SAXParser解析对象;
3、实例化CustomHandler(DefaultHandler的子类);
4、连接事件源对象XMLReader到事件处理类DefaultHandler中;
5、通过DefaultHandler返回我们需要的数据集合。
源码

 /*
    sax解析
     */
    public void sax(View view) throws IOException {

        InputStream is = getAssets().open("books.xml");
        parseXMLWithSAX(is);
    }
/*
    SAX解析的操作
     */
    private void parseXMLWithSAX(InputStream xmlData) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            XMLReader xmlReader = factory.newSAXParser().getXMLReader();
            ContentHandler handler = new ContentHandler();
            // 将ContentHandler的实例设置到XMLReader中
            xmlReader.setContentHandler(handler);
            // 开始执行解析
            xmlReader.parse(new InputSource(xmlData));//流数据
//            xmlReader.parse(new InputSource(new StringReader(xmlData)));//字符串数据
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
public class ContentHandler extends DefaultHandler {

    private String nodeName;

    private StringBuilder id;

    private StringBuilder name;

    private StringBuilder price;

    @Override
    public void startDocument() throws SAXException {
        id = new StringBuilder();
        name = new StringBuilder();
        price = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // 记录当前结点名
        nodeName = localName;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // 根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
        if ("id".equals(nodeName)) {
            id.append(ch, start, length);
        } else if ("name".equals(nodeName)) {
            name.append(ch, start, length);
        } else if ("price".equals(nodeName)) {
            price.append(ch, start, length);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ("book".equals(localName)) {
            Log.e("TAG", "SAX解析的子节点数据:" + "\n" +
                    "id :" + id.toString().trim() + "\n" +
                    "name : " + name.toString().trim() + "\n" +
                    "price : " + price.toString().trim());

            // 最后要将StringBuilder清空掉
            id.setLength(0);
            name.setLength(0);
            price.setLength(0);
        }
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

}

测试结果
Android数据解析之XML数据解析

PULL解析

定义
PULL的解析方式与SAX解析类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。
工作原理
PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。
常用方法
常用的接口类

接口和类名称 接口和类说明
XmlPullParser XML Pull解析接口,该接口定义了解析功能
XmlSerializer 它是一个接口,定义了XML信息集的序列
XmlPullParserFactory XML PULL解析工厂类,用于创建XML Pull解析器
XmlPullParserException 抛出单一的XML pull解析器相关的错误

常用方法

方法名 方法说明
getEventType() 该方法用于获取当前解析到的事件类型
nextText() 提取当前节点元素的字符数据
next() 获取下一个节点元素的类型
getName() 获取当前节点元素的名称
getAttributeCount() 获取当前节点属性的数量

XmlPullParser的接口类型

接口类型 接口类型说明
XmlPullParser.START_DOCUMENT 文档开始解析类型
XmlPullParser.END_DOCUMENT 文档结束解析类型
XmlPullParser.START_TAG 节点开始解析类型
XmlPullParser.END_TAG 节点结束解析类型
XmlPullParser.TEXT 文本解析类型

编程步骤
PULL解析XML的编程步骤:
1、获取PULL解析工厂实例对象;
2、使用XmlPullParserFactory的newPullParser()方法实例化PULL解析实例对象;
3、设置需解析的XML文件流和字符编码;
4、获取事件解析类型;
5、循环遍历解析,当文档解析结束时结束循环;

源码

  public void pull(View view) throws IOException {
        InputStream is = getAssets().open("books.xml");
        parseXMLWithPull(is);

        /*
        读取流数据
         */
        InputStreamReader inputStreamReader = new InputStreamReader(is);
        BufferedReader reader = new BufferedReader(inputStreamReader);
        String buf = null;
        String resultxml = "";

        StringBuffer sb = new StringBuffer();
        while ((buf = reader.readLine()) != null) {
            sb.append(buf);
            resultxml = sb.toString();
            Log.i("TAG", " resultxml--->" + sb.toString());
        }
        is.close();

    }
 /*
   Pull解析的操作
    */
    private void parseXMLWithPull(InputStream xmlData) {

        try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(xmlData, "UTF-8");//流数据
//            xmlPullParser.setInput(new StringReader(xmlData));//字符串数据
            int eventType = xmlPullParser.getEventType();
            String id = "";
            String name = "";
            String price = "";
            while (eventType != XmlPullParser.END_DOCUMENT) {
                String nodeName = xmlPullParser.getName();
                switch (eventType) {
                    // 开始解析某个结点
                    case XmlPullParser.START_TAG: {
                        if ("id".equals(nodeName)) {
                            id = xmlPullParser.nextText();
                        } else if ("name".equals(nodeName)) {
                            name = xmlPullParser.nextText();
                        } else if ("price".equals(nodeName)) {
                            price = xmlPullParser.nextText();
                        }
                        break;
                    }
                    // 完成解析某个结点
                    case XmlPullParser.END_TAG: {
                        if ("book".equals(nodeName)) {
                            Log.e("TAG", "Pull解析的子节点数据:" + "\n" +
                                    "id :" + id + "\n" +
                                    "name : " + name + "\n" +
                                    "price : " + price);

                        }
                        break;
                    }
                    default:
                        break;
                }
                eventType = xmlPullParser.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

测试结果
Android数据解析之XML数据解析

三种解析XML方法的比较

SAX解析器的特点:SAX解析器解析速度快、高效,占用内存少。但它的缺点是编码实现比其它解析方式更复杂,对于只需解析较少数量的XML文件时,使用SAX解析显得实现代码比较臃肿。

DOM解析器的特点:由于DOM在内存中是以树形结构存放的,那虽然检索和更新效率比较高,但对于使用DOM来解析较大数据的XML文件,将会消耗很大内存资源,这对于内存资源比较有限的手机设备来讲,是不太适合的。

PULL解析器的特点:PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用。Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。

测试Demo地址
github:https://github.com/TDCQZD/AndroidJson