Android 系列学习之XML文本数据解析
什么是XML? XML是一种扩展标志语言。标准通用标记语言的子类,一种标记电子文件使其具有结构性的标记语言,一种可以有用户自定义标志的的源语言。
XMl的特点:
- 一种标记语言,很类似HTML
- 其宗旨是传输数据
- 标签没有被预定义,用户需要自己定义标签
- 具有较好的自我秒描述性
- 是W3C推荐标准
- 纯文本信息
- 空格会被保留
XML与HTML有啥区别呢?
- XML旨在传输信息。XML被设置为传输和储存数据,焦点在数据内容;
- HTML旨在显示信息。HTML被设计问显示信息,焦点在信息的展示外观;
- XML的标签都没有预定义,需要用户自定义标签,HTML则是所有表亲都是预定义的。
常使用来解析XML数据的两种方式:SAX解析,在Android中较为流行的一种解析器;还有就是Document解析,在Android中,用的还是相对比较少的。
下面实例来比较一下两种的区别。
Document 解析:
步聚
- 获取document的解析工厂;DocumentBuilderFactory
- 获取DocumentBuilderFactory
- 获取Document实例
实例代码:
//获取Documen的解析工厂 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder(); //获取解析的器的对象Document // inputStream为读取本地XML文件获取到的inputStream或者是web获取的inputStream, // 这里使用的是获取web服务器上的XML文件的inputStream Document document = builder.parse(inputStream);
这样就可以轻松获取到Document的实例了,下面看一下解析XML数据,其实也是挺简单的。解析的数据文本是:
根据上述XML文本,解析数据
//获取XML文件的“根”元素包括的内容,即最外从元素包含的内容 Element documentElement = document.getDocumentElement(); //获取子对象的全部内容,返回一个包含全部子对象的队列 NodeList nodeList = documentElement.getElementsByTagName("user"); for (int i = 0; i < nodeList.getLength(); i++) { //获取到nodeList的每一个子对象 Element node = (Element) nodeList.item(i); //获取该对象node的属性 即数据的id String id = node.getAttribute("id"); //再获取node下的子元素 队列 NodeList nameList = node.getElementsByTagName("name"); NodeList sexList = node.getElementsByTagName("sex"); NodeList classesList = node.getElementsByTagName("classes"); //提取数据 String name = nameList.item(0).getTextContent(); String sex = sexList.item(0).getTextContent(); String classes = classesList.item(0).getTextContent(); Log.e("nodeAttribute", id); Log.e("name",name); Log.e("sex",sex); Log.e("classes",classes); }
下面看一下SAX解析XML文本数据。
SAX解析XML文档采用事件驱动模式。什么是事件驱动模式?它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理。
基于事件驱动的处理模式主要是基于事件源和事件处理器(或者叫监听器)来工作的。一个可以产生事件的对象叫做事件源,而一个可以针对事件做出响应的对象就被叫做事件处理器。
步聚:
- 创建DefaultHandler子类并实现一定相应的方法
- 创建解析器的工厂类SAXParserFactory
- 创建解析器的解析类SAXParser
- 获取XMLReader的实例
- 创建DefaultHandler子类注册到XMLReader当中
- 将从XML文件获取到的inputStream丢给XMLReader开始解析
实例代码:
//获取解析器工厂类 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); //获取解析器的解析类 SAXParser saxParser = saxParserFactory.newSAXParser(); //获取XMLReader实例 XMLReader xmlReader = saxParser.getXMLReader(); //XMLReader 与创建DefaultHandler子类关联(DefaultHandler注册到XMLReader) xmlReader.setContentHandler(new XMLHandlers()); //开始解析,InputStream为从本地读取XML文件获得的InputStream // 或者是从web上获取的InputStream xmlReader.parse(new InputSource(inputStream));
解析开始了,怎么来获取数据呢?还是用上面的XML文本数据
解析数据至少需要在创建DefaultHandler子类中复写以下三方法
/** * 开始读取元素 * * @param uri * @param localName 无前缀的标签 * @param qName 有前缀的标签 * @param attributes 属性集合 * @throws SAXException */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); Log.e("startElement", "startElement"); this.localName = localName; if ("user".equals(localName)) { for (int i = 0; i < attributes.getLength(); i++) { Log.e("user_id", attributes.getValue("id")); } } }
/** * 读取元素结束 * * @param uri * @param localName 无前缀 的标签 * @param qName 有前缀的标签 * @throws SAXException */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); Log.e("endElement", "endElement"); }
/** * 解析数据 * * @param ch 字符数组 * @param start 开始位置 * @param length 字符数组的长度 * @throws SAXException */ @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); Log.e("characters", "characters"); if (localName.equals("name")) { name = new String(ch, start, length); Log.e("name", name); } else if (localName.equals("sex")) { sex = new String(ch, start, length); Log.e("sex", sex); } else if (localName.equals("classes")) { classes = new String(ch, start, length); Log.e("classes", classes); } }
析出来的数据,有点儿难看,但是仔细看也不难,而且还会发现一点儿奇怪的东西。
09-17 15:05:10.637 2535-2553/? E/startDocument﹕ startDocument 09-17 15:05:10.639 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.639 2535-2553/? E/user_id﹕ 1 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/name﹕ gaosi 09-17 15:05:10.639 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/name﹕ [ 09-17 15:05:10.639 2535: 2553 E/characters ] characters 09-17 15:05:10.639 2535-2553/? E/name﹕ [ 09-17 15:05:10.639 2535: 2553 E/startElement ] startElement 09-17 15:05:10.639 2535-2553/? E/characters﹕ characters 09-17 15:05:10.639 2535-2553/? E/sex﹕ 男 09-17 15:05:10.639 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/sex﹕ [ 09-17 15:05:10.640 2535: 2553 E/characters ] characters 09-17 15:05:10.640 2535-2553/? E/sex﹕ [ 09-17 15:05:10.640 2535: 2553 E/startElement ] startElement 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/classes﹕ 3 09-17 15:05:10.640 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/characters ] characters 09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/endElement ] endElement 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/characters ] characters 09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/startElement ] startElement 09-17 15:05:10.640 2535-2553/? E/user_id﹕ 2 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.640 2535-2553/? E/characters﹕ characters 09-17 15:05:10.640 2535-2553/? E/name﹕ 张 09-17 15:05:10.641 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.641 2535-2553/? E/characters﹕ characters 09-17 15:05:10.641 2535-2553/? E/name﹕ [ 09-17 15:05:10.641 2535: 2553 E/characters ] characters 09-17 15:05:10.641 2535-2553/? E/name﹕ [ 09-17 15:05:10.641 2535: 2553 E/startElement ] startElement 09-17 15:05:10.641 2535-2553/? E/characters﹕ characters 09-17 15:05:10.641 2535-2553/? E/sex﹕ 男 09-17 15:05:10.641 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.641 2535-2553/? E/characters﹕ characters 09-17 15:05:10.641 2535-2553/? E/sex﹕ [ 09-17 15:05:10.641 2535: 2553 E/characters ] characters 09-17 15:05:10.641 2535-2553/? E/sex﹕ [ 09-17 15:05:10.642 2535: 2553 E/startElement ] startElement 09-17 15:05:10.642 2535-2553/? E/characters﹕ characters 09-17 15:05:10.642 2535-2553/? E/classes﹕ 3 09-17 15:05:10.642 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.642 2535-2553/? E/characters﹕ characters 09-17 15:05:10.642 2535-2553/? E/classes﹕ [ 09-17 15:05:10.642 2535: 2553 E/characters ] characters 09-17 15:05:10.642 2535-2553/? E/classes﹕ [ 09-17 15:05:10.642 2535: 2553 E/endElement ] endElement 09-17 15:05:10.642 2535-2553/? E/characters﹕ characters 09-17 15:05:10.642 2535-2553/? E/classes﹕ [ 09-17 15:05:10.643 2535: 2553 E/characters ] characters 09-17 15:05:10.643 2535-2553/? E/classes﹕ [ 09-17 15:05:10.643 2535: 2553 E/startElement ] startElement 09-17 15:05:10.643 2535-2553/? E/user_id﹕ 3 09-17 15:05:10.643 2535-2553/? E/characters﹕ characters 09-17 15:05:10.643 2535-2553/? E/characters﹕ characters 09-17 15:05:10.643 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.643 2535-2553/? E/characters﹕ characters 09-17 15:05:10.643 2535-2553/? E/name﹕ 李四 09-17 15:05:10.643 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.643 2535-2553/? E/characters﹕ characters 09-17 15:05:10.643 2535-2553/? E/name﹕ [ 09-17 15:05:10.643 2535: 2553 E/characters ] characters 09-17 15:05:10.643 2535-2553/? E/name﹕ [ 09-17 15:05:10.643 2535: 2553 E/startElement ] startElement 09-17 15:05:10.643 2535-2553/? E/characters﹕ characters 09-17 15:05:10.643 2535-2553/? E/sex﹕ 男 09-17 15:05:10.643 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.643 2535-2553/? E/characters﹕ characters 09-17 15:05:10.643 2535-2553/? E/sex﹕ [ 09-17 15:05:10.643 2535: 2553 E/characters ] characters 09-17 15:05:10.643 2535-2553/? E/sex﹕ [ 09-17 15:05:10.644 2535: 2553 E/startElement ] startElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/classes﹕ 2 09-17 15:05:10.644 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/characters ] characters 09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/endElement ] endElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/characters ] characters 09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/startElement ] startElement 09-17 15:05:10.644 2535-2553/? E/user_id﹕ 4 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/name﹕ 王 09-17 15:05:10.644 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/name﹕ [ 09-17 15:05:10.644 2535: 2553 E/characters ] characters 09-17 15:05:10.644 2535-2553/? E/name﹕ [ 09-17 15:05:10.644 2535: 2553 E/startElement ] startElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.644 2535-2553/? E/sex﹕ 女 09-17 15:05:10.644 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.644 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/sex﹕ [ 09-17 15:05:10.645 2535: 2553 E/characters ] characters 09-17 15:05:10.645 2535-2553/? E/sex﹕ [ 09-17 15:05:10.645 2535: 2553 E/startElement ] startElement 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/classes﹕ 2 09-17 15:05:10.645 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/classes﹕ [ 09-17 15:05:10.645 2535: 2553 E/characters ] characters 09-17 15:05:10.645 2535-2553/? E/classes﹕ [ 09-17 15:05:10.645 2535: 2553 E/endElement ] endElement 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/classes﹕[ 09-17 15:05:10.645 2535: 2553 E/characters ] characters 09-17 15:05:10.645 2535-2553/? E/classes﹕ [ 09-17 15:05:10.645 2535: 2553 E/startElement ] startElement 09-17 15:05:10.645 2535-2553/? E/user_id﹕ 5 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/startElement﹕ startElement 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/name﹕ 道 09-17 15:05:10.645 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.645 2535-2553/? E/characters﹕ characters 09-17 15:05:10.645 2535-2553/? E/name﹕ [ 09-17 15:05:10.645 2535: 2553 E/characters ] characters 09-17 15:05:10.645 2535-2553/? E/name﹕ [ 09-17 15:05:10.645 2535: 2553 E/startElement ] startElement 09-17 15:05:10.646 2535-2553/? E/characters﹕ characters 09-17 15:05:10.646 2535-2553/? E/sex﹕ 男 09-17 15:05:10.646 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.646 2535-2553/? E/characters﹕ characters 09-17 15:05:10.646 2535-2553/? E/sex﹕ [ 09-17 15:05:10.646 2535: 2553 E/characters ] characters 09-17 15:05:10.646 2535-2553/? E/sex﹕ [ 09-17 15:05:10.646 2535: 2553 E/startElement ] startElement 09-17 15:05:10.646 2535-2553/? E/characters﹕ characters 09-17 15:05:10.646 2535-2553/? E/classes﹕ 1 09-17 15:05:10.646 2535-2553/? E/endElement﹕ endElement 09-17 15:05:10.646 2535-2553/? E/characters﹕ characters 09-17 15:05:10.646 2535-2553/? E/classes﹕ [ 09-17 15:05:10.646 2535: 2553 E/characters ] characters 09-17 15:05:10.646 2535-2553/? E/classes﹕ [ 09-17 15:05:10.646 2535: 2553 E/endElement ] endElement 09-17 15:05:10.647 2535-2553/? E/characters﹕ characters 09-17 15:05:10.647 2535-2553/? E/classes﹕ [ 09-17 15:05:10.647 2535: 2553 E/characters ] characters 09-17 15:05:10.647 2535-2553/? E/classes﹕ [ 09-17 15:05:10.648 2535: 2553 E/characters ] characters 09-17 15:05:10.648 2535-2553/? E/classes﹕ [ 09-17 15:05:10.648 2535: 2553 E/characters ] characters 09-17 15:05:10.648 2535-2553/? E/classes﹕ [ 09-17 15:05:10.649 2535: 2553 E/endElement ] endElement 09-17 15:05:10.649 2535-2553/? E/endDocument﹕ endDocument
对比以下Document解析,你有没有发现一点东西?
SAX 是逐行从上往下解析的,变扫描边解析。而document解析则是将整个XML文本读取扫描完毕,在从外往里一层一层的解析。
聪明的人就会想到,这样的话,我利用SAX解析,解析达到一定的条件,终止解析XML数据,这样就会简单很多了吧。对的。怎么方法类中断呢?
查看上面的解析结果,发现endDocument()是调用一次,可不可以到达特定的条件时候,调用该方法类终止解析呢?还有一种也可以使用return 来终止解析,是否可以呢?这两个都是不行的。
不知道有没有发现DefaultHandler子类的复写方法都会抛异常, 我们只要在解析达到特定的条件时候,抛异常就OK了
在调用解析方法出捕获一下异常
try{ //XMLReader 与创建DefaultHandler子类关联(DefaultHandler注册到XMLReader) xmlReader.setContentHandler(new XMLHandlers()); //开始解析,InputStream为从本地读取XML文件获得的InputStream // 或者是从web上获取的InputStream xmlReader.parse(new InputSource(inputStream)); }catch (SAXException e){ //TODO去干中断解析的工作吧 //…… }
在characters()方法解析数据出等到达到特定条件就抛异常
if (localName.equals("name")) { name = new String(ch, start, length); Log.e("name", name); if (name.equals("gaosi")){ super.endDocument(); throw new SAXException("中断扫描,解析完成"); } }
在Android平台中,SAX解析更符合用户的而需求,不仅是简单,耗能少,耗时也少,内存需求少等