java pull 修改 xml_用SAX和PULL进行XML文件的解析与生成

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

1.SAX:

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

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

jack

c9a17dade24e24cb57eccef42357e2b7.png

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

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

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

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

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

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

如:从jack中得到【jack】

下面是实现代码:

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

/*** 通过sax进行解析

*@paramstr*/

public voidsax(String str) {//下面是固定的写法

SAXParserFactory factory =SAXParserFactory.newInstance();

XMLReader reader;try{//得到xmlReader对象

reader =factory.newSAXParser().getXMLReader();//设置内容处理器

reader.setContentHandler(newMyContentHandler());

reader.parse(new InputSource(newStringReader(str)));

}catch (SAXException | ParserConfigurationException |IOException e) {//TODO 自动生成的 catch 块

e.printStackTrace();

}

}

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

packagecom.kale.xml;importorg.xml.sax.Attributes;importorg.xml.sax.SAXException;importorg.xml.sax.helpers.DefaultHandler;/***@author:Jack Tony

* @tips :举个极端的例子:kale

* startElement中可以得到的是:type="hidden" name="UserType"

* characters中得到的是:kale

* @date :2014-10-11*/

public class MyContentHandler extendsDefaultHandler{//当前正在解析的标签名

privateString currentTag;/** 开始解析这个xml文件的时候触发*/@Overridepublic void startDocument() throwsSAXException {

System.out.println("开始解析这个文件了");

}/** 结束解析这个xml文件的时候触发*/@Overridepublic void endDocument() throwsSAXException {

System.out.println("文件解析结束");

}/** 开始解析每个元素的时候触发

*

* jack

* 1.uri:当前正在解析的元素的命名空间

* 2.localName:不带前缀的这个元素的名字——>name

* 3.qName:带前缀的这个元素命——>kale:name

* 4.attributes:得到的元素中的属性——>age=12 set=f*/@Overridepublic voidstartElement(String uri, String localName, String qName,

Attributes attributes)throwsSAXException {//举例:

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)

* 停止解析这个元素的时候触发*/@Overridepublic voidendElement(String uri, String localName, String qName)throwsSAXException {//TODO 自动生成的方法存根

super.endElement(uri, localName, qName);

System.out.println("————-解析"+qName+"标签结束————");

}/** 得到元素中的内容,比如下面的jack

* jack*/@Overridepublic void characters(char[] ch, int start, intlength)throwsSAXException {//举例:jack

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文件可能是不规范的,所以处理时要考虑异常):

jack

21

测试结果:

5c8e195900055f1a288e910486eca3c9.png

2.PULL

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

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

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

cd86ee41597aadeec7acec694005d85c.png

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

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

/*** 通过pull进行解析

*@paramstr*/

public voidpull(String str) {

XmlPullParser parser=Xml.newPullParser();

InputStream in= newByteArrayInputStream(str.getBytes());try{

parser.setInput(in,"utf-8");

MyXmlPullParserTask task= newMyXmlPullParserTask(parser);

task.execute();//开始解析文件

} catch(XmlPullParserException e) {

e.printStackTrace();

}

}

2.进行解析处理

MyXmlPullParserTask.java

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

packagecom.kale.xml;importjava.io.IOException;importorg.xmlpull.v1.XmlPullParser;importorg.xmlpull.v1.XmlPullParserException;public classMyXmlPullParserTask {/*** 当前正在解析的标签名,类似于sax中的localName

* 可以得到jack中【kale】*/

privateString currentTag;/*** 当前正在解析的标签名的前缀,sax中的qName=前缀+当前标签名

* 可以得到jack中【abc】*/

privateString currentPrefix;/*** 当前正在解析的标签的命名空间,类似于sax中的uri

* 得到

*

* jack

* 中的【http://schemas.android.com/apk/res/android】*/

privateString currentNamespace;privateXmlPullParser parser;publicMyXmlPullParserTask(XmlPullParser parser) {this.parser =parser;

}/*** 开始解析的方法,这里已经写好了,尽量不要该这里的代码。*/

public voidexecute() {try{//得到当前状态的标识代码

int eventCode =parser.getEventType();//如果当前状态不是文档结束,那么就继续循环

boolean flag = true;while(flag) {//当前解析元素的标签,不带前缀

currentTag =parser.getName();

currentNamespace=parser.getNamespace();

currentPrefix=parser.getPrefix();switch(eventCode) {caseXmlPullParser.START_DOCUMENT:

startDocument();break;caseXmlPullParser.END_DOCUMENT:

endDocument();

flag= false;//到文档末尾了,结束循环

break;caseXmlPullParser.START_TAG:

startElement(parser);

characters(parser);break;caseXmlPullParser.END_TAG:

endElement(parser);break;default:break;

}

eventCode=parser.next();

}

}catch (XmlPullParserException |IOException e) {

e.printStackTrace();

}

}/*** 开始解析文件时触发的方法*/

public voidstartDocument() {

System.out.println("开始解析这个文件了");

}/*** 结束解析这个xml文件的时候触发*/

public voidendDocument() {

System.out.println("该文件解析完成");

}/*** 开始解析某个标签时触发

* 可以得到jack中【sex=m age=21】部分

*@paramparser*/

public voidstartElement(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);

}

}/*** 结束解析某个标签时触发

* 遇到/>时表示一个标签解析完成,而遇到不会触发

*@paramparser*/

public voidendElement(XmlPullParser parser) {

System.out.println("————解析" + currentPrefix +":"+ currentTag + "标签结束————");

}/*** 解析标签中内容时触发

* 得到jack中【jack】的部分

*@paramparser

*@throwsXmlPullParserException

*@throwsIOException*/

public void characters(XmlPullParser parser) throwsXmlPullParserException, IOException {if (currentTag.equals("name")) {

System.out.println("name = " + parser.nextText());//会输出jack

} else if (currentTag.equals("age")) {

System.out.println("age = " + parser.nextText());//会输出21

}

}

}

测试样本:

jack

21

测试结果:

88a4d14d9576fc07deed008cc696259b.png

3.XML文件的生成

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

/*** 建立一个xml文件*/

public voidcreatXML() {

XmlSerializer serializer=Xml.newSerializer();

File file= new File(Environment.getExternalStorageDirectory(),"sharpandroid.xml");

FileOutputStream fos= null;try{

fos= newFileOutputStream(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();

}

}

}

测试结果:

c9998a658591fc07b69a243d2cc2edf9.png

全部activity中的代码

packagecom.kale.xml;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.StringReader;importjavax.xml.parsers.ParserConfigurationException;importjavax.xml.parsers.SAXParserFactory;importorg.xml.sax.InputSource;importorg.xml.sax.SAXException;importorg.xml.sax.XMLReader;importorg.xmlpull.v1.XmlPullParser;importorg.xmlpull.v1.XmlPullParserException;importorg.xmlpull.v1.XmlSerializer;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Environment;importandroid.util.Xml;importandroid.view.View;importandroid.widget.Toast;public class MainActivity extendsActivity {

@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

creatXML();

Toast.makeText(this, "xml文件建立成功,在SD卡根目录下sharpandroid.xml", 0).show();

}public voidbuttonListener(View v) {//从assets文件夹中得到test.xml文件的内容

String str = getFromAssets("test.xml");switch(v.getId()) {caseR.id.sax_button://通过sax进行文件的解析

sax(str);break;caseR.id.pull_button://通过pull来解析文件

pull(str);break;default:break;

}

}/*** 通过sax进行解析

*@paramstr*/

public voidsax(String str) {//下面是固定的写法

SAXParserFactory factory =SAXParserFactory.newInstance();

XMLReader reader;try{//得到xmlReader对象

reader =factory.newSAXParser().getXMLReader();//设置内容处理器

reader.setContentHandler(newMyContentHandler());

reader.parse(new InputSource(newStringReader(str)));

}catch (SAXException | ParserConfigurationException |IOException e) {//TODO 自动生成的 catch 块

e.printStackTrace();

}

}/*** 通过pull进行解析

*@paramstr*/

public voidpull(String str) {

XmlPullParser parser=Xml.newPullParser();

InputStream in= newByteArrayInputStream(str.getBytes());try{

parser.setInput(in,"utf-8");

MyXmlPullParserTask task= newMyXmlPullParserTask(parser);

task.execute();//开始解析文件

} catch(XmlPullParserException e) {

e.printStackTrace();

}

}/***@paramfileName

*@returnassets中文件的字符串*/

publicString getFromAssets(String fileName){

String result="";try{

InputStreamReader inputReader= newInputStreamReader( getResources().getAssets().open(fileName) );

BufferedReader bufReader= newBufferedReader(inputReader);

String line="";while((line = bufReader.readLine()) != null) {

result+=line;

}

}catch(Exception e) {

e.printStackTrace();

}returnresult;

}/*** 建立一个xml文件*/

public voidcreatXML() {

XmlSerializer serializer=Xml.newSerializer();

File file= new File(Environment.getExternalStorageDirectory(),"sharpandroid.xml");

FileOutputStream fos= null;try{

fos= newFileOutputStream(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();

}

}

}

}

布局文件:

2cbf6028f608aa25665f203a4e0630ff.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值