您的位置:首页 > 其它

DOM,SAX,PULL读写xml(初学、记录)

2015-04-07 15:26 190 查看
解析用到的xml文件,把它放在assets中了,food.xml

<?xml version="1.0" encoding="UTF-8" ?>
<breakfast_menu>
<food id="1">
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>

<food id="2">
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
</breakfast_menu>
对应的实体:Food类:

package pojo;

public class Food {

private int id;
private String name;
private String price;
private String description;
private int calories;

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 String getPrice() {
return price;
}

public void setPrice(String price) {
this.price = price;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public int getCalories() {
return calories;
}

public void setCalories(int calories) {
this.calories = calories;
}

@Override
public String toString() {
return "id:" + id + "\nname:" + name + "\nprice:" + price
+ "\ndescription:" + description + "\ncalories:" + calories+"\n--------------\n";
}
}

MainActivity类:(说明:layout_main中只有六个按钮,一个TextView,一个ScrollView)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import pojo.Food;

import DomMethod;
import PullMethod;
import SaxMethod;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
/*
* 总结:三种解析方式感觉DOM方式比较简单,但不适合大一点的文件,因为都不需要判断startElement和endElement
* 或者startTag和endTag,说明系统已经分解出来了,如果是大文件则会耗费大量的内存,不适合
* SAX方式:将xml文件节点分为ElementNode和TextNode两种
* PULL方式:将xml文件就分为tag标签,由tag类型来区分
*/
public class MainActivity extends Activity implements OnClickListener {

private TextView textView;
private Button mDomRead, mDomWrite, mSaxRead, mSaxWrite, mPullRead,
mPullWrite;
private SaxMethod saxMethod;
private DomMethod domMethod;
private PullMethod pullMethod;
private List<Food> foods;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();
saxMethod = new SaxMethod();
domMethod = new DomMethod();
pullMethod = new PullMethod();
}

/*
* 初始化
*/
private void initView() {
textView = (TextView) findViewById(R.id.textView);
mDomRead = (Button) findViewById(R.id.dom_read);
mDomWrite = (Button) findViewById(R.id.dom_write);
mSaxRead = (Button) findViewById(R.id.sax_read);
mSaxWrite = (Button) findViewById(R.id.sax_write);
mPullRead = (Button) findViewById(R.id.pull_read);
mPullWrite = (Button) findViewById(R.id.pull_write);
mDomRead.setOnClickListener(this);
mDomWrite.setOnClickListener(this);
mSaxRead.setOnClickListener(this);
mSaxWrite.setOnClickListener(this);
mPullRead.setOnClickListener(this);
mPullWrite.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.dom_read:
domRead();
break;
case R.id.dom_write:
domWrite();
break;
case R.id.sax_read:
saxRead();
break;
case R.id.sax_write:
saxWrite();
break;
case R.id.pull_read:
pullRead();
break;
case R.id.pull_write:
pullWrite();
break;
}
}

/*
* DOM方式解析xml
*/
private void domRead() {
try {
foods = domMethod.readXml(getAssets().open("food.xml"));
textView.append("\n Dom解析xml \n");
for (Food food : foods) {
textView.append(food.toString() + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

/*
* DOM方式生成xml
*/
private void domWrite() {
try {
String xml = domMethod.writeXml(foods);
writeToXml(xml);
} catch (Exception e) {
e.printStackTrace();
}
}

/*
* SAX方式解析xml
*/
private void saxRead() {
try {
InputStream xmlStream = getAssets().open("food.xml");
foods = saxMethod.getFoods(xmlStream);
textView.append("\n Sax解析xml \n");
for (Food food : foods) {
textView.append(food.toString() + "\n");
}
} catch (IOException e) {
e.printStackTrace();
}
}

/*
* SAX方式生成xml
*/
private void saxWrite() {
String xml = null;
try {
xml = saxMethod.serializeXml(foods);
writeToXml(xml);
} catch (Exception e) {
e.printStackTrace();
}
}

/*
* PULL方式解析xml
*/
private void pullRead() {
try {
InputStream xmlStream = getAssets().open("food.xml");
foods = pullMethod.parseXml(xmlStream);
textView.append("\n Pull解析xml \n");
for (Food food : foods) {
textView.append(food.toString() + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}

/*
* PULL方式生成xml
*/
private void pullWrite() {
String xml = null;
try {
xml = pullMethod.serializeXml(foods);
writeToXml(xml);
} catch (Exception e1) {
e1.printStackTrace();
}
}

/*
* 将字符串写入文件
*/
public void writeToXml(String content) {
try {
FileOutputStream fos = openFileOutput("breakfast.xml",
Context.MODE_PRIVATE);
fos.write(content.getBytes("UTF-8"));
Toast.makeText(MainActivity.this, "生成xml文件成功", Toast.LENGTH_SHORT)
.show();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}

}
SAX解析和生成xml:SaxMethod类
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
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;

import pojo.Food;

/*
* SAX解析XML步骤
* 1.创建XML解析处理器 SaxParserFactory
* 2.创建SAX解析器 SaxParser
* 3.将XML解析处理器分配给解析器 SaxParsex.parse()
* 4.对文档进行解析,将每个事件发送给处理器。
* 注意:节点有空白就读不出...例如:<name> example</name>则example读不到
*
* DOM:文档驱动。DOM在解析文件之前把整个文档装入内存,
* 处理大型文件时其性能很差,是由于DOM的树结构所造成的,此结构占用的内存较多。
* SAX:事件驱动型的XML解析方式。顺序读取XML文件,
* 不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,
* 会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,
* 适合对XML的顺序访问,且是只读的。
*/
public class SaxMethod extends DefaultHandler {

private List<Food> foods = null;
private Food food = null;
private String TAG = null; // 记录上一个节点的名称

public List<Food> getFoods(InputStream xmlStream) {
SaxMethod handle = new SaxMethod();
// 先创建一个SAXParserFactory解析模式,Parser解析,只能通过newInstance方法创建,是抽象类
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// SAXParser也是一个抽象类,记得看源码
SAXParser parser = factory.newSAXParser();
parser.parse(xmlStream, handle);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
4000
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return handle.getFoods();
}

public List<Food> getFoods() {
return foods;
}

/*
* 调用startDocument()方法,开始解析xml文件
*/
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("-->>开始解析xml文件");
foods = new ArrayList<Food>();
}

/*
* 处理ElementNode节点 像<food><name>这样的都是ElementNode,通过startElement方法解析
* 而<name>Strawberry</name>里面的Strawberry是TextNode,通过characters方法解析 <food
* id="">里面的id属性可以通过attributes.getValue(0)获得,如果有多个属性依次类推
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if ("food".equals(qName)) {
food = new Food();
food.setId(Integer.parseInt(attributes.getValue(0)));
}
// 将正在处理的节点赋值给TAG
TAG = qName;
}

/*
* 执行到</food>时调用endElement方法
*
* @param qName表示当前正在处理的节点的名称
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
System.out.println("-->>当前节点:" + qName);
if ("food".equals(qName)) {
foods.add(food);
food = null;
}
TAG = null;
}

/*
* 解析TextNode代码
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
if (TAG != null) {
String content = new String(ch, start, length);
if ("name".equals(TAG)) {
food.setName(content);
} else if ("price".equals(TAG)) {
food.setPrice(content);
} else if ("description".equals(TAG)) {
food.setDescription(content);
} else if ("calories".equals(TAG)) {
food.setCalories(Integer.parseInt(content));
}
}
}

/*
* 序列化,实际上就是将List<Food>里面的值通过xml序列化转化为xml格式的文本类型,
* 然后返回这个文本类型,最后将这个String类型的数据通过文件IO输出到文件中
*/
public String serializeXml(List<Food> foods) throws Exception {
// 看SAXTransformFactory和TransformFactory源码,都是抽象类,但SAXTransformFactory是TransformFactory的子类,而且SAXTransformFactory并没有可是实例化的方法
// 因此找到父类,父类有实例化的方法newInstance方法,做一个类型转换即可
SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory
.newInstance();
TransformerHandler handler = factory.newTransformerHandler();
Transformer transformer = handler.getTransformer();

// 设置输出采用的编码方式
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// 是否自动添加额外的空白 indent内缩
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// 是否忽略XML声明
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

// 将结果放入到StringWriter中
StringWriter writer = new StringWriter();
Result result = new StreamResult(writer);
handler.setResult(result);

String uri = "";
String localName = "";
// interface TransformerHandler extends ContentHandler, LexicalHandler,
// DTDHandler
// 开始执行转换xml格式,和endDocument成对出现类似于先声明我要进行xml操作,然后声明xml操作结束
// 这句执行之后出现<?xml version="1.0" encoding="UTF-8" ?>
// 前面设置了不可忽略xml声明,因此会出现这句
handler.startDocument();
// 写第一个节点,即出现<breakfast_menu>,后面相应的要出现</breakfast_menu>节点
handler.startElement(uri, localName, "breakfast_menu", null);

// 负责存放元素的属性信息
AttributesImpl atts = new AttributesImpl();
char ch[] = null;
for (Food food : foods) {
// 先清空属性集,防止上一个节点的值对当前节点造成影响
atts.clear();
atts.addAttribute(uri, localName, "id", "String", String.valueOf(food.getId()));
// <food id="">
handler.startElement(uri, localName, "food", atts);
// 下面四句效果:<name>food.getName()</name>
handler.startElement(uri, localName, "name", null);
ch = food.getName().toCharArray();
handler.characters(ch, 0, ch.length);
handler.endElement(uri, localName, "name");
// 以下依次类推...
handler.startElement(uri, localName, "price", null);
ch = food.getPrice().toCharArray();
handler.characters(ch, 0, ch.length);
handler.endElement(uri, localName, "price");

handler.startElement(uri, localName, "description", null);
ch = food.getDescription().toCharArray();
handler.characters(ch, 0, ch.length);
handler.endElement(uri, localName, "description");

handler.startElement(uri, localName, "calories", null);
ch = String.valueOf(food.getCalories()).toCharArray();
handler.characters(ch, 0, ch.length);
handler.endElement(uri, localName, "calories");

// </food>
handler.endElement(uri, localName, "food");
}
// </breakfast_menu>
handler.endElement(uri, localName, "breakfast_menu");
handler.endDocument();
return writer.toString();
}
}
DOM解析和生成:DomMethod类
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
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.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import pojo.Food;

public class DomMethod {

public List<Food> readXml(InputStream is) throws Exception {
List<Food> foods = new ArrayList<Food>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(is);
Element element = document.getDocumentElement();
NodeList foodsx = element.getElementsByTagName("food");
for (int i = 0; i < foodsx.getLength(); i++) {
Food food = new Food();
Element foodx = (Element) foodsx.item(i);
food.setId(Integer.parseInt(foodx.getAttribute("id")));
food.setName(foodx.getElementsByTagName("name").item(0)
.getTextContent());
food.setPrice(foodx.getElementsByTagName("price").item(0)
.getTextContent());
food.setDescription(foodx.getElementsByTagName("description")
.item(0).getTextContent());
food.setCalories(Integer.parseInt(foodx
.getElementsByTagName("calories").item(0).getTextContent()));
foods.add(food);
}
return foods;
}

public String writeXml(List<Food> foods) throws Exception {
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document newxml = builder.newDocument();
// breakfast_menu节点
Element breakfast = newxml.createElement("breakfast_menu");
// <food></food>以及里面的属性和元素
for (Food food : foods) {
Element foodx = newxml.createElement("food");
foodx.setAttribute("id", String.valueOf(food.getId()));
Element name = newxml.createElement("name");
name.setTextContent(food.getName());
Element price = newxml.createElement("price");
price.setTextContent(food.getPrice());
Element description = newxml.createElement("description");
description.setTextContent(food.getDescription());
Element calories = newxml.createElement("calories");
calories.setTextContent(String.valueOf(food.getCalories()));
// 将food节点下的元素放入food下
foodx.appendChild(name);
foodx.appendChild(price);
foodx.appendChild(description);
foodx.appendChild(calories);
// 将food元素放入breakfast_menu里面
breakfast.appendChild(foodx);
}
// 最后将breakfast_menu放入newxml中,到此xml就创建成功
newxml.appendChild(breakfast);

TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
// 设置输出采用的编码方式
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// 是否自动添加额外的空白 indent内缩
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// 是否忽略XML声明
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

StringWriter writer = new StringWriter();
Result result = new StreamResult(writer);
transformer.transform(new DOMSource(newxml), result);

return writer.toString();
}

}
PULL解析和生成xml:PullMethod类
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;

import android.util.Xml;
import pojo.Food;

public class PullMethod {

/*
* 解析xml,思路: 由事件类型决定,先得到类型getEventType() 由类型判断当前解析的节点到底为哪个,有START_DOCUMENT
* 开始解析文件 END_DOCUMENT 解析完成, START_TAG 开始标签,如<food> END_TAG 结束标签,如</food>
* 其实就是遍历整个文件,对不同的节点类型做不同的处理,用next()方法控制解析位置移动
*
* @param is,可以通过getAssets().open(file)获得
*/
public List<Food> parseXml(InputStream is) throws Exception {
List<Food> foods = null;
Food food = null;
// 创建实例
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, "UTF-8");
// 获取类型,在XmlPullParser源码中有int类型值 START_DOCUMENT = 0
// END_DOCUMENT = 1、START_TAG = 2、END_TAG = 3、TEXT = 4等
int type = parser.getEventType();
// 当前位置不为结束元素时,继续解析
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
// 开始解析
case XmlPullParser.START_DOCUMENT:
foods = new ArrayList<Food>();
break;
// 解析标签
case XmlPullParser.START_TAG:
// 得到当前标签名
String tag = parser.getName();
// 解析标签为<food>,而food标签有属性
if (tag.equals("food")) {
food = new Food();
// 获取属性值
food.setId(Integer.parseInt(parser.getAttributeValue(0)));
} else if (tag.equals("name")) {
type = parser.next();
// 输出结果为4,表示TEXT,由此可见上面的意思其实就是把类型指到TEXT
// 然后才可以用getText()解析到,否则解析得为null
System.out.println("-->>type:" + type);
food.setName(parser.getText());
} else if (tag.equals("price")) {
type = parser.next();
food.setPrice(parser.getText());
} else if (tag.equals("description")) {
type = parser.next();
food.setDescription(parser.getText());
} else if (tag.equals("calories")) {
type = parser.next();
food.setCalories(Integer.parseInt(parser.getText()));
}
break;
case XmlPullParser.END_TAG:
// 当解析完一个food时
if (parser.getName().equals("food")) {
foods.add(food);
food = null;
}
break;
}
type = parser.next();
}
return foods;
}

public String serializeXml(List<Food> foods) throws Exception {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlSerializer serializer = factory.newSerializer();

StringWriter writer = new StringWriter();
serializer.setOutput(writer);

serializer.startDocument("UTF-8",false);
String namespace = "";
serializer.startTag(namespace, "breakfast_menu");
for (Food food : foods) {
// <food>
serializer.startTag(namespace, "food");
serializer.attribute(namespace, "id", String.valueOf(food.getId()));
// <name> </name>
serializer.startTag(namespace, "name");
serializer.text(food.getName());
serializer.endTag(namespace, "name");
// <price> </price>
serializer.startTag(namespace, "price");
serializer.text(food.getPrice());
serializer.endTag(namespace, "price");
// <description> </description>
serializer.startTag(namespace, "description");
serializer.text(food.getDescription());
serializer.endTag(namespace, "description");
// <calories> </calories>
serializer.startTag(namespace, "calories");
serializer.text(String.valueOf(food.getCalories()));
serializer.endTag(namespace, "calories");
// </food>
serializer.endTag(namespace, "food");
}
serializer.endTag(namespace, "breakfast_menu");
serializer.endDocument();
return writer.toString();
}

}


生成的xml文件在File Explore 下data->data->项目包->files下,导出即可查看

注:查阅了很多资料,不列举了,抓紧时间学习~~

另外:解释都在代码里,而且关键性的思想不太知道,大家见谅

SAX和PULL方式的区别确实不知道,只是知道用Pull方式比较好而已,还需继续学习...

革命尚未成功,同志仍需努力!

主要参考:

http://blog.csdn.net/liuhe688/article/details/6415593 

http://www.iteye.com/topic/763895

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