您的位置:首页 > 移动开发 > Android开发

Android 创建与解析XML(一)---- SAX方式

2014-02-11 11:39 465 查看
在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>





得到的结果图,如下:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: