XML解析有传统的dom方法还有Jsoup,SAX,PULL等,这里讲的是比较省内存的SAX和PULL方法。Android中极力推荐用PULL的方式来解析,我个人觉得pull确实比较简单,但其内部的逻辑性不是很分明。所以今天做了个类来将其中的多个步骤进行了分割,以后直接拿来用即可。

1.SAX:

首先先讲解SAX中各个方法的作用:

我们以这个不规则的xml语句做例子:

<abc:kale sex=m age=21>jack</abc:kale>

startDocument:开始解析一个xml文件时触发

endDocument:这个xml文件被解析完毕时触发

startElement:开始解析xml文件中的一个标签时触发,这里可以得到标签名和其中的各个属性值。

如:从<person age = 12 sex = f/>会得到标签名:【person】和属性值:【age = 12 sex = f】

endElement:结束解析一个标签时触发

characters:解析这个标签内部的内容时触发,这里可以得到这个标签子节点中的内容。

如:从<name>jack<name>中得到【jack】

下面是实现代码:

1.首先建立一个SAX对象,然后进行解析工作。这里会要自己建立一个ContentHandler的子类

/**
* 通过sax进行解析
* @param str
*/
public void sax(String str) {
//下面是固定的写法
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader;
try {
//得到xmlReader对象
reader = factory.newSAXParser().getXMLReader();
//设置内容处理器
reader.setContentHandler(new MyContentHandler());
reader.parse(new InputSource(new StringReader(str))); } catch (SAXException | ParserConfigurationException | IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}

MyContentHandler.java 这个类就是来处理事务的,里面有各种回调方法

package com.kale.xml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; /**
* @author:Jack Tony
* @tips :举个极端的例子:<input type="hidden" name="UserType">kale</input>
* startElement中可以得到的是:type="hidden" name="UserType"
* characters中得到的是:kale
* @date :2014-10-11
*/
public class MyContentHandler extends DefaultHandler{
//当前正在解析的标签名
private String currentTag; /*
* 开始解析这个xml文件的时候触发
*/
@Override
public void startDocument() throws SAXException {
System.out.println("开始解析这个文件了");
} /*
* 结束解析这个xml文件的时候触发
*/
@Override
public void endDocument() throws SAXException {
System.out.println("文件解析结束");
} /*
* 开始解析每个元素的时候触发
* <person age = 12 sex = f/>
* <kale:name>jack<kale:name>
* 1.uri:当前正在解析的元素的命名空间
* 2.localName:不带前缀的这个元素的名字——>name
* 3.qName:带前缀的这个元素命——>kale:name
* 4.attributes:得到的元素中的属性——>age=12 set=f
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//举例:<input type="hidden" name="UserType" id="UserType" value="1">
currentTag = localName;//input
System.out.println("————开始解析"+qName+"这个标签了————"); for (int i = 0; i < attributes.getLength(); i++) {
String name = attributes.getLocalName(i);//第一次是:type
String value = attributes.getValue(i);//第一次是:hidden
System.out.println(name + " = " + value);
} } /* (非 Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
* 停止解析这个元素的时候触发
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO 自动生成的方法存根
super.endElement(uri, localName, qName);
System.out.println("————-解析"+qName+"标签结束————");
} /*
* 得到元素中的内容,比如下面的jack
* <name>jack<name>
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//举例:<name>jack<name>
if (currentTag.equals("name")) {
System.out.println("name = " + new String(ch,start,length));//会输出jack
}
if (currentTag.equals("age")) {
System.out.println("age = " + new String(ch,start,length));//会输出21
}
}
}

贴上测试样本(由于xml文件可能是不规范的,所以处理时要考虑异常):

<?xml version="1.0" encoding="utf-8"?>
<namespace xmlns:abc="http://schemas.android.com/apk/res/android">
<form id="form1" name="form1" method="post" action="ok" style="margin: 0; padding: 0;" >
<input type="hidden" name="UserType" id="12" value="1"/>
<abc:name>jack</abc:name>
<abc:age>21</abc:age>
</form>
</namespace>

测试结果:

2.PULL

其实PULL中就一个重要的方法XmlPullParser.next();,正因如此才让其变得简单很多。PULL的特点是运行到什么状态是没有回调方法的,它进行某个处理状态时,会改变一个状态变量,通过getEventType()就可以来判断当前是处于什么状态了。

推荐浏览:http://384444165.iteye.com/blog/1521332

但正因为内部逻辑需要开发者来处理,所以变得结构不是很清晰。我这里通过一个类来将其转换为SAX的框架,以后只需要复写这些方法便可以直接进行操作了。至于运行到哪一步,看方法名酒明白了。同样还是之前的那幅图:

这里面的方法的作用也是和SAX一样的。下面是使用的代码:

1.建立这个类的对象,执行操作

    /**
* 通过pull进行解析
* @param str
*/
public void pull(String str) {
XmlPullParser parser = Xml.newPullParser();
InputStream in = new ByteArrayInputStream(str.getBytes());
try {
parser.setInput(in,"utf-8");
MyXmlPullParserTask task = new MyXmlPullParserTask(parser);
task.execute();//开始解析文件
} catch (XmlPullParserException e) {
e.printStackTrace();
}
}

2.进行解析处理

MyXmlPullParserTask.java

我通过前面的switch-case语句将处理的状态进行了分割,这些状态可以完全类比到SAX中。这样便于理解!

package com.kale.xml;

import java.io.IOException;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; public class MyXmlPullParserTask {
/**
* 当前正在解析的标签名,类似于sax中的localName
* 可以得到<abc:kale sex=m age=21>jack</abc:kale>中【kale】
*/
private String currentTag; /**
* 当前正在解析的标签名的前缀,sax中的qName=前缀+当前标签名
* 可以得到<abc:kale sex=m age=21>jack</abc:kale>中【abc】
*/
private String currentPrefix; /**
* 当前正在解析的标签的命名空间,类似于sax中的uri
* 得到
* <namespace xmlns:abc="http://schemas.android.com/apk/res/android">
* <abc:kale sex=m age=21>jack</abc:kale>
* 中的【http://schemas.android.com/apk/res/android】
*/
private String currentNamespace; private XmlPullParser parser; public MyXmlPullParserTask(XmlPullParser parser) {
this.parser = parser;
} /**
* 开始解析的方法,这里已经写好了,尽量不要该这里的代码。
*/
public void execute() {
try {
// 得到当前状态的标识代码
int eventCode = parser.getEventType();
// 如果当前状态不是文档结束,那么就继续循环
boolean flag = true;
while (flag) {
// 当前解析元素的标签,不带前缀
currentTag = parser.getName();
currentNamespace = parser.getNamespace();
currentPrefix = parser.getPrefix(); switch (eventCode) {
case XmlPullParser.START_DOCUMENT:
startDocument();
break;
case XmlPullParser.END_DOCUMENT:
endDocument();
flag = false;// 到文档末尾了,结束循环
break;
case XmlPullParser.START_TAG:
startElement(parser);
characters(parser);
break;
case XmlPullParser.END_TAG:
endElement(parser);
break;
default:
break;
}
eventCode = parser.next();
}
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
}
} /**
* 开始解析文件时触发的方法
*/
public void startDocument() {
System.out.println("开始解析这个文件了");
} /**
* 结束解析这个xml文件的时候触发
*/
public void endDocument() {
System.out.println("该文件解析完成");
} /**
* 开始解析某个标签时触发
* 可以得到<abc:kale sex=m age=21>jack</abc:kale>中【sex=m age=21】部分
* @param parser
*/
public void startElement(XmlPullParser parser) {
System.out.println("————开始解析" + currentPrefix +":"+ currentTag + "这个标签了————"); for (int i = 0; i < parser.getAttributeCount(); i++) {
String name = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
System.out.println(name + " = " + value);
}
} /**
* 结束解析某个标签时触发
* 遇到/>时表示一个标签解析完成,而遇到</xxx>不会触发
* @param parser
*/
public void endElement(XmlPullParser parser) {
System.out.println("————解析" + currentPrefix +":"+ currentTag + "标签结束————");
} /**
* 解析标签中内容时触发
* 得到<name>jack</name>中【jack】的部分
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
public void characters(XmlPullParser parser) throws XmlPullParserException, IOException {
if (currentTag.equals("name")) {
System.out.println("name = " + parser.nextText());// 会输出jack
} else if (currentTag.equals("age")) {
System.out.println("age = " + parser.nextText());// 会输出21
}
}
}

测试样本:

<?xml version="1.0" encoding="utf-8"?>
<namespace xmlns:abc="http://schemas.android.com/apk/res/android">
<form id="form1" name="form1" method="post" action="ok" style="margin: 0; padding: 0;" >
<input type="hidden" name="UserType" id="12" value="1"/>
<abc:name>jack</abc:name>
<abc:age>21</abc:age>
</form>
</namespace>

测试结果:

3.XML文件的生成

生成是用简单的pull来做的,没啥技术含量,就是用代码来写xml,最后放到sd卡中

    /**
* 建立一个xml文件
*/
public void creatXML() {
XmlSerializer serializer = Xml.newSerializer();
File file = new File(Environment.getExternalStorageDirectory(),"sharpandroid.xml");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
serializer.setOutput(fos, "UTF-8"); serializer.startDocument("UTF-8", true);
//命名空间+标签名,命名空间可以=null
serializer.startTag(null, "namespace");
serializer.attribute("http://schemas.android.com/apk/res/android", "abc", "egf"); serializer.startTag(null, "persons");
for (int i = 0; i < 2; i++) {
serializer.startTag(null, "person");
serializer.attribute(null, "id", i+1+"");
serializer.attribute(null, "age", i+10+""); serializer.startTag(null, "name");
serializer.text("jack");
serializer.endTag(null, "name"); serializer.endTag(null, "person");
}
serializer.endTag(null, "persons");
serializer.endTag(null, "namespace");
serializer.endDocument(); } catch (IllegalArgumentException | IllegalStateException | IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
finally {
try {
fos.flush();
fos.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} }
}

测试结果:

全部activity中的代码

package com.kale.xml;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer; import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Xml;
import android.view.View;
import android.widget.Toast; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
creatXML();
Toast.makeText(this, "xml文件建立成功,在SD卡根目录下sharpandroid.xml", 0).show();
} public void buttonListener(View v) {
//从assets文件夹中得到test.xml文件的内容
String str = getFromAssets("test.xml");
switch (v.getId()) {
case R.id.sax_button:
//通过sax进行文件的解析
sax(str);
break;
case R.id.pull_button:
//通过pull来解析文件
pull(str);
break; default:
break;
}
} /**
* 通过sax进行解析
* @param str
*/
public void sax(String str) {
//下面是固定的写法
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader;
try {
//得到xmlReader对象
reader = factory.newSAXParser().getXMLReader();
//设置内容处理器
reader.setContentHandler(new MyContentHandler());
reader.parse(new InputSource(new StringReader(str))); } catch (SAXException | ParserConfigurationException | IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
} /**
* 通过pull进行解析
* @param str
*/
public void pull(String str) {
XmlPullParser parser = Xml.newPullParser();
InputStream in = new ByteArrayInputStream(str.getBytes());
try {
parser.setInput(in,"utf-8");
MyXmlPullParserTask task = new MyXmlPullParserTask(parser);
task.execute();//开始解析文件
} catch (XmlPullParserException e) {
e.printStackTrace();
}
} /**
* @param fileName
* @return assets中文件的字符串
*/
public String getFromAssets(String fileName){
String result="";
try {
InputStreamReader inputReader = new InputStreamReader( getResources().getAssets().open(fileName) );
BufferedReader bufReader = new BufferedReader(inputReader);
String line="";
while((line = bufReader.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 建立一个xml文件
*/
public void creatXML() {
XmlSerializer serializer = Xml.newSerializer();
File file = new File(Environment.getExternalStorageDirectory(),"sharpandroid.xml");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
serializer.setOutput(fos, "UTF-8"); serializer.startDocument("UTF-8", true);
//命名空间+标签名,命名空间可以=null
serializer.startTag(null, "namespace");
serializer.attribute("http://schemas.android.com/apk/res/android", "abc", "egf"); serializer.startTag(null, "persons");
for (int i = 0; i < 2; i++) {
serializer.startTag(null, "person");
serializer.attribute(null, "id", i+1+"");
serializer.attribute(null, "age", i+10+""); serializer.startTag(null, "name");
serializer.text("jack");
serializer.endTag(null, "name"); serializer.endTag(null, "person");
}
serializer.endTag(null, "persons");
serializer.endTag(null, "namespace");
serializer.endDocument(); } catch (IllegalArgumentException | IllegalStateException | IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
finally {
try {
fos.flush();
fos.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} }
} }

布局文件:

<RelativeLayout 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"
tools:context="${relativePackage}.${activityClass}" > <Button
android:id="@+id/sax_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="通过SAX来解析"
android:onClick="buttonListener"/> <Button
android:id="@+id/pull_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="通过PULL来解析"
android:onClick="buttonListener"/> </RelativeLayout>

源码下载:http://download.csdn.net/detail/shark0017/8028375

用SAX和PULL进行XML文件的解析与生成的更多相关文章

  1. [置顶] Android开发之XML文件的解析

    Android系统开发之XML文件的解析 我们知道Http在网络传输中的数据组织方式有三种分别为:XML方式.HTML方式.JSON方式.其中XML为可扩展标记语言,如下: <?xml vers ...

  2. 【文件处理】xml 文件 DOM解析

    一.Java解析xml.解析xml四种方法.DOM.SAX.JDOM.DOM4j.XPath 此文针对其中的DOM方法具体展开介绍及代码分析 sax.dom是两种对xml文档进行解析的方法(没有具体实 ...

  3. JDOM方法实现对XML文件的解析

    首先要下载JDOM.jar包,下载地址:http://download.csdn.net/detail/ww6055/8880371 下载到JDOM.jar包之后导入到工程中去. 实例程序: book ...

  4. xml文件的解析

    1. xml文件的解析 void CDataMgr::readStringData() { std::string xml_name = "config/string.xml"; ...

  5. 类的反射及xml文件的解析

    类的反射 xml文件的解析 .properties||.xml配置文件的创建及读取内容 //创建对象 Properties properties = new Properties(); //存储 pr ...

  6. JAVA读取XML文件并解析获取元素、属性值、子元素信息

    JAVA读取XML文件并解析获取元素.属性值.子元素信息 关键字 XML读取  InputStream   DocumentBuilderFactory   Element     Node 前言 最 ...

  7. Java中使用DOM4J来生成xml文件和解析xml文件

    一.前言 现在有不少需求,是需要我们解析xml文件中的数据,然后导入到数据库中,当然解析xml文件也有好多种方法,小编觉得还是DOM4J用的最多最广泛也最好理解的吧.小编也是最近需求里遇到了,就来整理 ...

  8. DOM、SAX、JDOM、DOM4J以及PULL在XML文件解析中的工作原理以及优缺点对比

    1. DOM(Document Object Model)文档对象模型1. DOM是W3C指定的一套规范标准,核心是按树形结构处理数据,DOM解析器读入XML文件并在内存中建立一个结构一模一样的&qu ...

  9. XML文件的解析—DOM、SAX

    一.DOM 解析 思路:获得Document对象,遍历其中节点获得需要的内容 要点: Document :  DocuemntBuilderFactory --newDocumentBuilder - ...

随机推荐

  1. .NetCore 下使用多个DbContext

    一个项目中使用多个DbContext 或者种数据库的多个DbContext 业务需要 单个DbContext使用不需要给出说明 1.dotnet ef migrations add migration ...

  2. Vue.js学以致用之遇到的那些坑

    前段时间的react授权许可的闹剧告诉大家一个问题,只有自己的东西用着才放心.各大巨头也逐渐明白使用自家东西的优势.本来vue的生态就愈加火热,这次的闹剧无疑又加速了vue的发展.当下,国内越来越多的 ...

  3. eclipse launching workspace太慢的解决方法

    这几天eclipse调试Android项目的时候反应超慢,右下显示launching workspace就不怎么动了,今天终于卡的受不了了,在网上搜了写方法,设置了下总算好点了,现在把方法贴出来,跟大 ...

  4. VB.NET中lambda的写法

    lambda 或者叫匿名方法 '有返回值的匿名函数,func前面输入参数,最后一个输出参数 Dim func1 As Func(Of Integer, Integer) = Function(ByVa ...

  5. JAVA JMX协议监控

    JMX协议监控,可通过JMX协议远程监控,实时监控线上jvm情况,并通过平台管理界面进行 展示,可以通过监控实时获得线上服务器运行情况. 可以监控内存.实时线程.共享内存等各种信息. 获取实时线程信息 ...

  6. hdu 4431 第37届ACM/ICPC 天津赛区现场赛A题 枚举

    题意:就是给了13张牌.问增加哪些牌可以胡牌.m是数字,s是条,p是筒,c是数字 胡牌有以下几种情况: 1.一个对子 +  4组 3个相同的牌或者顺子.  只有m.s.p是可以构成顺子的.东西南北这样 ...

  7. 【BZOJ-1913】signaling信号覆盖 极角排序 + 组合

    1913: [Apio2010]signaling 信号覆盖 Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1232  Solved: 506[Subm ...

  8. 【转载】CMenu自绘---钩子---去除边框

    使用默认的CMenu菜单类或者继承CMenu实现的菜单扩展类,在显示的时候最外层都会有边框出现,或者说是具有3D外观(菜单阴影不算),当改变菜单背景色或者需要加个边框线时就会看上去很不美观.看过很多菜 ...

  9. git 用户名和密码保存

    git config --global credential.helper store 输入一次后,后续不再需要输入用户名密码

  10. HDU 4751 Divide Groups (2013南京网络赛1004题,判断二分图)

    Divide Groups Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...