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

1 篇文章 0 订阅
1 篇文章 0 订阅

解析用到的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();
		} 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
继续学习,加油...


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值