在Android中,常见的解析XML文档的方式有:SAX解析器,DOM解析器,PULL解析器。

先了解一下SAX解析的方法。

SAX解析器:

SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。

SAX解析器优点:

1、顺序读入文档并产生相应事件,可以处理任何大小的XML文档

2、解析速度快,占用内存少

3、对开发人员而言更灵活,可以用SAX创建自己的XML对象模型

SAX解析器缺点:

1、只能对文档按顺序解析一遍,不支持对文档的随意访问

2、只能读取XML文档内容,而不能修改

3、开发上比较复杂,需要自己来实现事件处理器

先在项目的assets目录中放置一个XML文档books.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<id>1</id>
<name>Android 学习精要</name>
<price>79.00</price>
</book>
<book>
<id>2</id>
<name>Android 应用开发揭秘</name>
<price>69.00</price>
</book>
</books>

采用SAX解析器的具体处理步骤:

1、创建SAXParserFactory对象

2、根据SAXParserFactory.newSAXParser()方法返回一个SAXParser解析器

3、实例化一个DefaultHandler对象

4、调用SAXParser的parse方法从输入源中获取到的xml数据

5、通过DefaultHandler返回我们需要的数据集合

重点在于DefaultHandler对象中对每一个元素节点,属性,文本内容,文档内容进行处理。

前面说过DefaultHandler是基于事件处理模型的,基本处理方式是:当SAX解析器导航到文档开始标签时回调startDocument方法,导航到文档结束标签时回调endDocument方法。当SAX解析器导航到元素开始标签时回调startElement方法,导航到其文本内容时回调characters方法,导航到标签结束时回调endElement方法。

根据以上的解释,我们可以得出以下处理xml文档逻辑:

1、当导航到文档开始标签时,在回调函数startDocument中,可以不做处理,当然你可以验证下UTF-8、实例化一个集合用来存贮list等等。

2、当导航到books开始标签时,在调用方法startElement。

3、导航到book开始标签时,就说明需要实例化Book对象了,当然book标签也可以有属性,如果有实例化Book后还必须取出属性值,attributes.getValue(NAME),同时赋予book对象中,同时添加为导航到的book标签添加一个boolean为真的标识,用来说明导航到了book元素。

4、当然有book标签内还有子标签(节点),但是SAX解析器是不知道导航到什么标签的,它只懂得开始,结束而已。那么如何让它认得我们的各个标签呢?当然需要判断了,于是可以使用回调方法startElement中的参数String localName,把我们的标签字符串与这个参数比较下,就可以了。我们还必须让SAX知道,现在导航到的是某个标签,因此添加一个true属性让SAX解析器知道。

5、它还会导航到文本内标签,(就是<name></name>里面的内容),回调方法characters,我们一般在这个方法中取出就是<name></name>里面的内容,并保存。

6、当然它是一定会导航到结束标签</book> 或者</books>的,如果是</book>标签,记得把book对象添加进list中。如果是book中的子标签</name>,就将取得的值添加到book的name属性中。

Book.java

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;
}

@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", price=" + price + "]";
}

}

先自定义一个解析器接口BookParser.java

/**
*
*/
package com.sym.xml;

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

/**
* @author sym
*
*/
public interface BookParser {

/**
* 解析输入流,得到Book对象集合
* @param is
* @return
* @throws Exception
*/
public List<Book> parser(InputStream is) throws Exception;

/**
* 序列化Book对象,得到XML形式的字符串
* @param books
* @return
* @throws Exception
*/
public String serialize(List<Book> books) throws Exception;
}

SaxBookParser.java

package com.sym.xml;

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 implements BookParser {

@Override
public List<Book> parser(InputStream is) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();//取得SAXParserFactory实例
SAXParser parser = factory.newSAXParser();//从factory获取SAXParser实例
MyHandler handler = new MyHandler();
parser.parse(is, handler);
return handler.getBooks();
}

@Override
public String serialize(List<Book> books) throws Exception {
SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();//取得SAXTransformerFactory实例
TransformerHandler handler = factory.newTransformerHandler();//从factory获取TransformerFactory实例
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 = 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();
}

private class MyHandler extends DefaultHandler{
private List<Book> books;
private Book book;
private StringBuilder builder;

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

@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
books = new ArrayList<Book>();
builder = new StringBuilder();
}

@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
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 {
// TODO Auto-generated method stub
super.characters(ch, start, length);
builder.append(ch, start, length);//将读取的字符数组追加到builder中
}

@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
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);
}
}

}
}

MainActivity.java

package com.sym.xml;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

private static final String TAG = "XML";
private BookParser parser;
private List<Book> books;
private TextView readxml, writerxml;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
readxml = (TextView) this.findViewById(R.id.readxml);
writerxml = (TextView) this.findViewById(R.id.writerxml);
}

public void read(View v){
try {
InputStream is = getAssets().open("books.xml");
parser = new SaxBookParser();//创建SaxBookParser实例
//parser = new DomBookParser();
//parser = new PullBookParser();
books = parser.parser(is);//解析输入流
StringBuffer sb = new StringBuffer();
sb.append("解析XML结果:" + "\n");
for(Book book : books){
sb.append(book.toString() + "\n");
Log.i(TAG, book.toString());
}
readxml.setText(sb.toString());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}

}

public void writer(View v){
try {
if(parser != null){
String xml = parser.serialize(books);
FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);
fos.write(xml.getBytes("UTF-8"));
StringBuffer sb = new StringBuffer();
sb.append("创建XML结果:"+"\n");
sb.append(xml);
writerxml.setText(sb.toString());
}else{
Toast.makeText(this, "请先解析XML!", Toast.LENGTH_LONG).show();
}

} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}

}

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="
http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>

<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解析XML"
android:onClick="read" />

<TextView
android:id="@+id/readxml"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解析XML结果:"
/>

<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="创建XML"
android:onClick="writer" />

<TextView
android:id="@+id/writerxml"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="创建XML结果:"
/>

</LinearLayout>


得到的结果图,如下:

更多相关文章

  1. 安全新手入坑——HTML标签
  2. Android自定义控件系列九:从源码看Android触摸事件分发机制
  3. Android8.0 存储系统
  4. 条件数据库Android:sqllite的简单使用
  5. Android(安卓)JSON:Gson,FastJson解析库的使用和对比分析
  6. Android(安卓)AccessibilityService机制源码解析
  7. Android学习感悟之消息机制
  8. 信息提醒之Notification,兼容全部SDK-更新中
  9. Android自定义Lint实践

随机推荐

  1. android 通过webservice方式向服务器上传
  2. Android中自定义Dialog常用的两种方式
  3. Android去除默认USB调试授权确认框
  4. android 拍照
  5. Android之手机壁纸的改变
  6. Android学习笔记(四) android 更换桌面壁
  7. Android中编译工具链的改动----LLVM份量
  8. Android调用系统程序
  9. android 中让activity全屏幕显示
  10. android 打开 url 方式