android开发笔记之解析XML
来源:互联网 发布:数控机床数据采集 编辑:程序博客网 时间:2024/05/27 21:07
前言
公司客户需求中有一个内置几个电话号码,看了一下以前工程师的代码,是采用xml文件的形式来配置几个号码,然后对应的把xml文件解析,再将这些号码插入到contacts的db数据库中。正好借这个机会,学习一下xml文件的解析。
xml解析的简单介绍
XML文件作为承载数据的一个重要角色,非常非常用户来配置和客置化,所以读写XML文件是Android开发中一项重要的技能。
在Android中,常见的XML解析器分别为SAX解析器、DOM解析器和PULL解析器:
- SAX解析器
SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。
- DOM解析器:
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。
分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。
- PULL解析器:
PULL解析器的运行方式和SAX类似,都是基于事件的模式。
不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。
PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
一个完整的Demo
我们的项目代码结构:
先在assets目录中放置一个XML文档book.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>
再定义一个Book.java类:
package com.example.android.xml.util;public class Book { private int id; private String name; private float prince; public Book(int id, String name, float prince) { this.id = id; this.name = name; this.prince = prince; } public Book() { } 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 getPrince() { return prince; } public void setPrince(float prince) { this.prince = prince; } @Override public String toString() { return "Book{" + "id=" + id + ", name='" + name + '\'' + ", prince=" + prince + '}'; }}
再定义一个Util 类:
public class Util { public static final String ITEMS = "books"; public static final String ITEM = "book"; public static final String KEY_1 = "id"; public static final String KEY_2 = "name"; public static final String KEY_3 = "price";}
最后,我们还要把这个xml文件读取的数据生成一个新的XML文档,文档路径/data/data//files/books.xml,当然查看这个路径需要userdebug或debug版本。
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="1001"> <name>Thinking In Java</name> <price>80.0</price> </book> <book id="1002"> <name>Core Java</name> <price>90.0</price> </book> <book id="1003"> <name>Hello, Andriod</name> <price>100.0</price> </book> </books>
然后,我们定义一个IParse.java文件,这是一个接口,声明了一个parse方法:
import java.io.InputStream;import java.util.List;public interface IParse { public List<Book> parse(InputStream is) throws Exception;}
然后分别实现此parse方法:
SAXParse.java 实现接口IParse,用SAX的方法解析xml文件:
import android.util.Log;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;import java.io.InputStream;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;public class SAXParse implements IParse { public static final String TAG = "SAXParse"; @Override 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(); } //需要重写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(); Log.i(TAG, "--------MyHandler----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); Log.i(TAG, "--------MyHandler----startElement---------"); Log.i(TAG, "--------MyHandler----startElement---------localName:"+localName); if (localName.equals(Util.ITEM)) { book = new Book(); } builder.setLength(0); //将字符长度设置为0 以便重新开始读取元素内的字符节点 } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); Log.i(TAG, "--------MyHandler----characters---------"); Log.i(TAG, "--------MyHandler----characters---------builder:"+builder); builder.append(ch, start, length); //将读取的字符数组追加到builder中 } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); Log.i(TAG, "--------MyHandler----endElement---------"); Log.i(TAG, "--------MyHandler----endElement---------localName:"+localName); Log.i(TAG, "--------MyHandler----endElement---------builder:"+builder); if (localName.equals(Util.KEY_1)) { book.setId(Integer.parseInt(builder.toString())); } else if (localName.equals(Util.KEY_2)) { book.setName(builder.toString()); } else if (localName.equals(Util.KEY_3)) { book.setPrince(Float.parseFloat(builder.toString())); } else if (localName.equals(Util.ITEM)) { books.add(book); } } }}
DOMParse.java 实现接口IParse,用DOM的方法解析xml文件:
import android.util.Log;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import java.io.InputStream;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;public class DOMParse implements IParse { public static final String TAG = "DOMParse"; @Override public List<Book> parse(InputStream is) throws Exception{ List<Book> books = new ArrayList<Book>(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); Element rootElement = doc.getDocumentElement(); NodeList items = rootElement.getElementsByTagName(Util.ITEM); 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(); Log.i(TAG, "nodeName:" + nodeName); if (nodeName.equals(Util.KEY_1)) { Log.i(TAG, "property.getFirstChild().getNodeValue():" + property.getFirstChild().getNodeValue()); book.setId(Integer.parseInt(property.getFirstChild().getNodeValue())); } else if (nodeName.equals(Util.KEY_2)) { Log.i(TAG, "property.getFirstChild().getNodeValue():" + property.getFirstChild().getNodeValue()); book.setName(property.getFirstChild().getNodeValue()); } else if (nodeName.equals(Util.KEY_3)) { Log.i(TAG, "property.getFirstChild().getNodeValue():" + property.getFirstChild().getNodeValue()); book.setPrince(Float.parseFloat(property.getFirstChild().getNodeValue())); } } books.add(book); } return books; }}
PULLParse .java 实现接口IParse,用PULL的方法解析xml文件:
import android.util.Log;import android.util.Xml;import org.xmlpull.v1.XmlPullParser;import java.io.InputStream;import java.util.ArrayList;import java.util.List;public class PULLParse implements IParse { public static final String TAG = "PULLParse"; @Override public List<Book> parse(InputStream is) throws Exception { List<Book> books = null; Book book = null; XmlPullParser parser = Xml.newPullParser(); parser.setInput(is, "UTF-8"); int eventType = parser.getEventType(); Log.i(TAG,"eventType:"+eventType); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_DOCUMENT: Log.i(TAG,"---------------START_DOCUMENT--------------------"); Log.i(TAG,"XmlPullParser.START_DOCUMENT"); Log.i(TAG,"parser.getName():"+parser.getName()); books = new ArrayList<Book>(); break; case XmlPullParser.START_TAG: Log.i(TAG,"-----------------START_TAG------------------"); Log.i(TAG,"XmlPullParser.START_TAG"); Log.i(TAG,"parser.getName():"+parser.getName()); if (parser.getName().equals(Util.ITEM)) { book = new Book(); } else if (parser.getName().equals(Util.KEY_1)) { eventType = parser.next(); Log.i(TAG,"parser.getText():"+parser.getText()); book.setId(Integer.parseInt(parser.getText())); } else if (parser.getName().equals(Util.KEY_2)) { eventType = parser.next(); Log.i(TAG,"parser.getText():"+parser.getText()); book.setName(parser.getText()); } else if (parser.getName().equals(Util.KEY_3)) { eventType = parser.next(); Log.i(TAG,"parser.getText():"+parser.getText()); book.setPrince(Float.parseFloat(parser.getText())); } break; case XmlPullParser.END_TAG: Log.i(TAG,"---------------END_TAG--------------------"); Log.i(TAG,"XmlPullParser.END_TAG:"); Log.i(TAG,"parser.getName():"+parser.getName()); if (parser.getName().equals(Util.ITEM)) { books.add(book); book = null; } break; } eventType = parser.next(); } return books; }}
我们再定义一个序列化接口ISerialize,主要是把从xml文件中读取来的数据重新写到xml文件中:
import java.util.List;public interface ISerialize { public String serialize(List<Book> books) throws Exception;}
对应的,我们再分别用三种方式来实现:
SAXSerialize.java: 用SAX的方式来实现接口ISerialize:
import android.util.Log;import org.xml.sax.helpers.AttributesImpl;import java.io.StringWriter;import java.util.List;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;public class SAXSerialize implements ISerialize { public static final String TAG = "SAXSerialize"; @Override public String serialize(List<Book> books) throws Exception { //取得SAXTransformerFactory实例 SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance(); //从factory获取TransformerHandler实例 TransformerHandler handler = factory.newTransformerHandler(); //从handler获取Transformer实例 Transformer transformer = handler.getTransformer(); // 设置输出采用的编码方式 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // 是否自动添加额外的空白 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // 是否忽略XML声明 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); StringWriter writer = new StringWriter(); Result result = new StreamResult(writer); handler.setResult(result); //代表命名空间的URI 当URI无值时 须置为空字符串 String uri = ""; //命名空间的本地名称(不包含前缀) 当没有进行命名空间处理时 须置为空字符串 String localName = ""; handler.startDocument(); handler.startElement(uri, localName, "books", null); //负责存放元素的属性信息 AttributesImpl attrs = new AttributesImpl(); char[] ch = null; for (Book book : books) { attrs.clear(); //清空属性列表 //添加一个名为id的属性(type影响不大,这里设为string) attrs.addAttribute(uri, localName, "id", "string", String.valueOf(book.getId())); //开始一个book元素 关联上面设定的id属性 handler.startElement(uri, localName, "book", attrs); //开始一个name元素 没有属性 handler.startElement(uri, localName, "name", null); ch = String.valueOf(book.getName()).toCharArray(); //设置name元素的文本节点 handler.characters(ch, 0, ch.length); handler.endElement(uri, localName, "name"); //开始一个price元素 没有属性 handler.startElement(uri, localName, "price", null); ch = String.valueOf(book.getPrince()).toCharArray(); //设置price元素的文本节点 handler.characters(ch, 0, ch.length); handler.endElement(uri, localName, "price"); handler.endElement(uri, localName, "book"); } handler.endElement(uri, localName, "books"); handler.endDocument(); Log.i(TAG, "SAXSerialize---serialize--writer.toString():"+writer.toString()); return writer.toString(); }}
DOMSerialize.java: 用DOM的方式来实现接口ISerialize:
import android.util.Log;import org.w3c.dom.Document;import org.w3c.dom.Element;import java.io.StringWriter;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;public class DOMSerialize implements ISerialize { public static final String TAG = "DOMSerialize"; @Override 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.getPrince() + ""); 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); //开始转换 Log.i(TAG, "SAXSerialize---serialize--writer.toString():" + writer.toString()); return writer.toString(); }}
PULLSerialize.java: 用PULL的方式来实现接口ISerialize:
import android.util.Log;import android.util.Xml;import org.xmlpull.v1.XmlSerializer;import java.io.StringWriter;import java.util.List;public class PULLSerialize implements ISerialize { public static final String TAG = "PULLSerialize"; @Override 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.getPrince() + ""); serializer.endTag("", "price"); serializer.endTag("", "book"); } serializer.endTag("", "books"); serializer.endDocument(); Log.i(TAG, "PULLSerialize---serialize--writer.toString():" + writer.toString()); return writer.toString(); }}
我们界面如下:
其中成局文件如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.example.android.xml.MainActivity" tools:showIn="@layout/activity_main"> <Button android:id="@+id/sax_parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="clickSaxParse" android:text="sax parse xml"/> <Button android:id="@+id/sax_serialize" android:layout_toRightOf="@+id/sax_parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="clickSaxSerialize" android:text="sax serialize xml"/> <Button android:id="@+id/dom_parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/sax_parse" android:onClick="clickDomParse" android:text="dom parse xml"/> <Button android:id="@+id/dom_serialize" android:layout_toRightOf="@+id/dom_parse" android:layout_alignBottom="@+id/dom_parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="clickDomParseSerialize" android:text="Dom serialize xml"/> <Button android:id="@+id/pull_parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/dom_parse" android:onClick="clickPullParse" android:text="pull parse xml"/> <Button android:id="@+id/pull_serialize" android:layout_toRightOf="@+id/pull_parse" android:layout_alignBottom="@+id/pull_parse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="clickPullParseSerialize" android:text="pull serialize xml"/></RelativeLayout>
然后在activity中实现的逻辑如下:
import android.content.Context;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.util.Log;import android.view.View;import com.example.android.xml.util.Book;import com.example.android.xml.util.DOMParse;import com.example.android.xml.util.DOMSerialize;import com.example.android.xml.util.IParse;import com.example.android.xml.util.ISerialize;import com.example.android.xml.util.PULLParse;import com.example.android.xml.util.PULLSerialize;import com.example.android.xml.util.SAXParse;import com.example.android.xml.util.SAXSerialize;import java.io.FileOutputStream;import java.io.InputStream;import java.util.List;public class MainActivity extends AppCompatActivity { public final static String TAG ="MainActivity"; private IParse parse; private ISerialize serialize; private List<Book> books = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } public void clickSaxParse(View view){ Log.i(TAG, "clickSaxParse"); try { InputStream is = getAssets().open("book.xml"); parse = new SAXParse();// parse = new DomParser();// parse = new PULLParse(); books = parse.parse(is); } catch (Exception e) { e.printStackTrace(); } printBooks(); } public void clickDomParse(View view){ Log.i(TAG,"clickDomParse"); try { InputStream is = getAssets().open("book.xml");// parse = new SAXParser(); parse = new DOMParse();// parse = new PULLParse(); books = parse.parse(is); } catch (Exception e) { e.printStackTrace(); } printBooks(); } public void clickPullParse(View view){ Log.i(TAG,"clickPullParse"); try { InputStream is = getAssets().open("book.xml");// parse = new SAXParser();// parse = new DomParser(); parse = new PULLParse(); books = parse.parse(is); } catch (Exception e) { e.printStackTrace(); } printBooks(); } public void clickSaxSerialize(View view){ Log.i(TAG, "clickSaxSerialize"); try { serialize = new SAXSerialize(); //序列化 String xml = serialize.serialize(books); FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE); fos.write(xml.getBytes("UTF-8")); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } public void clickDomParseSerialize(View view){ Log.i(TAG,"clickDomParseSerialize"); try { serialize = new DOMSerialize(); //序列化 String xml = serialize.serialize(books); FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE); fos.write(xml.getBytes("UTF-8")); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } public void clickPullParseSerialize(View view){ Log.i(TAG, "clickPullParseSerialize"); try { serialize = new PULLSerialize(); //序列化 String xml = serialize.serialize(books); FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE); fos.write(xml.getBytes("UTF-8")); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } public void printBooks(){ for (Book book : books) { Log.i(TAG, book.toString()); } }}
总结
对于这三种解析器各有优点,因为SAX解析器操作起来太笨重,DOM不适合文档较大,内存较小的场景,唯有PULL轻巧灵活,速度快,占用内存小,使用非常顺手,所以android开发推荐PULL解析器。
参考资料
(1) Android中解析XML
http://blog.csdn.net/liuhe688/article/details/6415593
(2)【Android】实现XML解析的几种技术
http://www.cnblogs.com/weixing/archive/2013/08/07/3243366.html
- android开发笔记之解析XML
- android开发笔记之PULL解析xml文件
- android 开发之解析xml
- Android 开发之 XML 解析
- Android开发之XML解析——SAX解析XML
- Android学习笔记--解析XML之SAX
- android学习笔记之-xml pull解析
- Android笔记之xml(SAX)解析
- Android开发之XML文件解析
- android开发之sax解析xml文档
- Android开发之xml解析技术
- Android开发之XML文件解析
- Android开发之XML文件的解析
- Android开发学习之Xml解析归纳
- Android开发之解析XML-SAX
- Android开发基础之XML解析
- Android开发之XML文件解析
- Android开发之xml的解析
- 回过头再看 计算机体系结构2----缓存cache
- js入门小练习:网页计算器
- 用css3实现各种图标效果
- 游戏服务器压力测试总结
- enum应用示例
- android开发笔记之解析XML
- Java中如何将int 类型转换为 Long类型
- Flume单机安装并且测试
- RecycleView 实现复杂首页布局三种方式
- MariaDB Galera Cluster 部署(mysql 集群部署)
- VUE.JS——组件基础
- mysql 手动锁表
- 代码中直接添加图片与文字Android
- UIScrollView-iOS10-Apple官方文档翻译注释总结