在网络上传输数据时最常用的格式有两种,XML和JSON,下面首先学一下如何解析XML格式的数据,JSON的解析可以参见我的博客(android基础---->JSON数据的解析)。解析XML 格式的数据其实也有挺多种方式的,本节中我们学习比较常用的两种,Pull解析和SAX 解析。
目录导航
一、我们常用的五个事件:
二、PULL解析的步骤:
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput ( new FileReader (filename ) );
三、next()方法与nextToken()方法:
<?xml version="1.0" encoding="utf-8"?> <LOL> <person> <!-- 这里是盖伦的注释 --> <name sex="man">盖伦</name> <address>德玛西亚</address> <say>我将带头冲锋</say> </person> <person> <!-- 这里是亚索的注释 --> <name sex="man">亚索</name> <address>艾欧尼亚</address> <say>死亡如风,常伴吾身</say> </person> <person> <!-- 这里是瑞雯的注释 --> <name sex="girl">瑞雯</name> <address>诺克萨斯</address> <say>战争与谋杀之间,潜藏着我们的心魇</say> </person> </LOL>
// 得到xml的数据 private String getXMLData(String fileName) { StringBuffer stringBuffer = new StringBuffer(); InputStream inputStream = null; BufferedReader bufferedReader = null; try { inputStream = getResources().getAssets().open(fileName); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line = ""; while ((line = bufferedReader.readLine()) != null) { stringBuffer.append(line + "\n"); } bufferedReader.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } if (inputStream != null) { inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } Log.i(TAG, stringBuffer.toString()); return stringBuffer.toString(); }
// pull解析xml数据 public void pullParse(View view) { String xmlData = getXMLData(fileName); try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xmlPullParser = factory.newPullParser(); xmlPullParser.setInput(new StringReader(xmlData)); int eventType = xmlPullParser.getEventType(); String name = ""; String address = ""; String say = ""; String sex = ""; while (eventType != XmlPullParser.END_DOCUMENT) { String nodeName = xmlPullParser.getName(); switch (eventType) { case XmlPullParser.START_TAG: { if ("name".equals(nodeName)) { // sex与name的位置不能互换 // sex = xmlPullParser.getAttributeValue(0); sex = xmlPullParser.getAttributeValue(null, "sex"); name = xmlPullParser.nextText(); } else if ("address".equals(nodeName)) { address = xmlPullParser.nextText(); } else if ("say".equals(nodeName)) { say = xmlPullParser.nextText(); } break; } // 完成解析某个结点 case XmlPullParser.END_TAG: { if ("person".equals(nodeName)) { Log.d(TAG, "name: " + name); Log.d(TAG, "address: " + address); Log.d(TAG, "say: " + say); Log.d(TAG, "sex: " + sex); } break; } default: break; } eventType = xmlPullParser.next(); } } catch (Exception e) { e.printStackTrace(); } }
// 增加一个case,用于接收注释的事件 case XmlPullParser.COMMENT: { coment = xmlPullParser.getText(); break; } default: break; } eventType = xmlPullParser.nextToken(); // 此处为修改部分
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name: 盖伦 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: address: 德玛西亚 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say: 我将带头冲锋 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex: man 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: comment: 这里是盖伦的注释 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name: 亚索 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: address: 艾欧尼亚 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say: 死亡如风,常伴吾身 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex: man 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: comment: 这里是亚索的注释 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name: 瑞雯 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: address: 诺克萨斯 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say: 战争与谋杀之间,潜藏着我们的心魇 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex: girl 03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: comment: 这里是瑞雯的注释
一、 SAX解析的简要:
SAX:事件驱动型的XML解析方式。顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问,且是只读的。由于移动设备的内存资源有限,SAX的顺序读取方式更适合移动开发。
二、 SAX解析XML步骤:
三、SAX解析的过程:
package com.example.linux.xmlparsetest; import android.util.Log; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Created by Linux on 2016/3/16. */ public class ContentHandler extends DefaultHandler { private final static String TAG = "MainActivity"; private String nodeName; private StringBuilder name; private StringBuilder address; private StringBuilder say;private StringBuilder sex; // 文档开始时执行 @Override public void startDocument() throws SAXException { name = new StringBuilder(); address = new StringBuilder(); say = new StringBuilder(); sex = new StringBuilder(); coment = new StringBuilder(); } // 元素开始时执行 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 记录当前结点名 nodeName = localName; if (nodeName.equals("name") && attributes != null) { sex.append(attributes.getValue("sex")); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // 根据当前的结点名判断将内容添加到哪一个StringBuilder对象中 if ("name".equals(nodeName)) { name.append(ch, start, length); } else if ("address".equals(nodeName)) { address.append(ch, start, length); } else if ("say".equals(nodeName)) { say.append(ch, start, length); } } // 元素结束时执行 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("person".equals(localName)) { Log.d(TAG, "name is " + name.toString().trim()); Log.d(TAG, "adress is " + address.toString().trim()); Log.d(TAG, "say is " + say.toString().trim()); Log.d(TAG, "sex is " + sex.toString().trim()); // 最后要将StringBuilder清空掉 name.setLength(0); address.setLength(0); say.setLength(0); sex.setLength(0); } } // 文档结束时 @Override public void endDocument() throws SAXException { super.endDocument(); } }
// sax解析数据 public void saxParse(View view) { String xmlData = getXMLData(fileName); try { SAXParserFactory factory = SAXParserFactory.newInstance(); XMLReader xmlReader = factory.newSAXParser().getXMLReader(); ContentHandler handler = new ContentHandler(); // 将ContentHandler的实例设置到XMLReader中 xmlReader.setContentHandler(handler); // 开始执行解析 xmlReader.parse(new InputSource(new StringReader(xmlData))); } catch (Exception e) { e.printStackTrace(); } }
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name is 盖伦 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: adress is 德玛西亚 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say is 我将带头冲锋 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex is man 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name is 亚索 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: adress is 艾欧尼亚 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say is 死亡如风,常伴吾身 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex is man 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name is 瑞雯 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: adress is 诺克萨斯 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say is 战争与谋杀之间,潜藏着我们的心魇 03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex is girl
区别:
相似性:
Pull解析器也提供了类似SAX的事件,开始文档START_DOCUMENT和结束文档END_DOCUMENT,开始元素START_TAG和结束元素END_TAG,遇到元素内容TEXT等,但需要调用next() 方法提取它们(主动提取事件)。
使用:
如果在一个XML文档中我们只需要前面一部分数据,但是使用SAX方式或DOM方式会对整个文档进行解析,尽管XML文档中后面的大部分数据我们其实都不需要解析,因此这样实际上就浪费了处理资源。使用PULL方式正合适。
源码下载 访问密码 2c66
至于SAX解析能不能解析到注释的内容,不知道各位有没有结果?