Android Sax解析XML出现空值或脏数据的解决方案
2016-06-16 20:19
405 查看
Java解析XML一般有两种方案,一种是pull,一种是Sax解析。两种解析原理是不太一样的,但各有优势。先来说说他们的原理以及优缺点。
pull解析XML是将整块XML文件读入手机内存再进行树形解析,对于内存小的手机自然是会有卡顿的反应,而且解析的途中无法停止,倘若一个xml有几十M,效率还蛮低,但是解析出的数据信息是对称的,也就是成功率很高。
Sax(全 称 Simple API for XML)解析是将XML逐行解析,程序运行时占用内存不大,非常适合手机等嵌入式设备,但代码写起来的时候有些怪异,而且解析途中会莫名其妙出现空值或脏 数据,这让我非常苦闷,不过解决方法还是有的。还有一个优点就是可以随时停止解析,毕竟它是逐行解析。想了解更多详见Java API的org.xml.sax。
现在来说说Sax的运行机制:
//声明SAX解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//通过解析工厂类构造XMLReader对象
XMLReader reader = factory.newSAXParser().getXMLReader();
//通过reander对象设置ContentHandler
reader.setContentHandler(new MyContentHandler());
//将想要解析的数据传入reader对象
reader.parse(new InputSource(new StringReader(result)));
以上是调用Sax时的核心源码,不要问为什么这么写,以现在的知识储备还无法回答,但这是官方API提供的方法,使用起来确实让人迥异万分。而 MyContentHandler 这个类需要自己重写,这个要继承DefaultHandler。
MyContentHandler详细代码:
package so.orion.XMLSax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyContentHandler extends DefaultHandler {
String name = "", sex = "", age = "", address = "";
String tagName ;
String temp ="" ;
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//System.out.println("Test—>" + this.tagName + "—" + new String (ch , start , length) );
String sb = new String(ch, start, length);
temp = temp + sb;
}
@Override
public void endDocument() throws SAXException {
System.out.println("…………..end…………..");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if( localName.equals( "student" )){
this.printAll();
}
if( tagName.equals("name")){
this.name = temp;
}else if( tagName.equals("sex")){
this.sex = temp;
}else if( tagName.equals("age")){
this.age = temp;
}else if( tagName.equals("address")){
this.address = temp;
}
}
@Override
public void startDocument() throws SAXException {
System.out.println("…………..begin…………..");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
this.tagName = localName ;
this.temp = "";
if( tagName.equals("student") ){
System.out.println("————————————–");
for( int i = 0 ; i<attributes.getLength() ; i++ ){
System.out.println( attributes.getLocalName(i) + " : "+attributes.getValue(i) );
}
}
}
public void printAll( ){
System.out.println("Name : " + this.name);
System.out.println("Sex : " + this.sex);
System.out.println("Age : " + this.age);
System.out.println("Address : " + this.address);
}
}
网上提供的简单解析过程是:startDocument->startElement->characters->endElement->endDocument
清晰点的详解图应该是:
解析器没有解析完标签时会在 startElement 和 endElement之间循环,但是我实验得出的结论是:
startDocument之后还会执行一次characters,而不知何种原因数据量非常非常小的时候characters也会自动解析多次。
说说我遇到的问题,源数据如下:
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="1240">
<name>Tony</name>
<sex>boy</sex>
<age>22</age>
<address>G301</address>
</student>
<student id="1241">
<name>John</name>
<sex>boy</sex>
<age>21</age>
<address>G302</address>
</student>
<student id="1243">
<name>Sally</name>
<sex>girl</sex>
<age>21</age>
<address>T2132</address>
</student>
<student id="1244">
<name>Tom</name>
<sex>boy</sex>
<age>23</age>
<address>G303</address>
</student>
</students>
解析时出现空数据:
网上的大神在数据处理时将成员变量在characters中做赋值判断处理,而我仿照时出现的问题怪异,于是小弟将判断处理这个代码写在 endElement里,每次标签结束后再对当前成员变量进行赋值操作,而characters无论执行多少次,我只要在成员变量声明一个String temp,在characters中执行String sb = new String(ch,start,length); temp = temp + sb ; ,在下一个startElement开始的时候再将temp赋值为空就可以了。无论中间如何执行数据都不会丢失或出现脏数据的情况,即使遇到换行符也是一样可以多次执行。
修改后的代码执行后结果:
pull解析XML是将整块XML文件读入手机内存再进行树形解析,对于内存小的手机自然是会有卡顿的反应,而且解析的途中无法停止,倘若一个xml有几十M,效率还蛮低,但是解析出的数据信息是对称的,也就是成功率很高。
Sax(全 称 Simple API for XML)解析是将XML逐行解析,程序运行时占用内存不大,非常适合手机等嵌入式设备,但代码写起来的时候有些怪异,而且解析途中会莫名其妙出现空值或脏 数据,这让我非常苦闷,不过解决方法还是有的。还有一个优点就是可以随时停止解析,毕竟它是逐行解析。想了解更多详见Java API的org.xml.sax。
现在来说说Sax的运行机制:
//声明SAX解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//通过解析工厂类构造XMLReader对象
XMLReader reader = factory.newSAXParser().getXMLReader();
//通过reander对象设置ContentHandler
reader.setContentHandler(new MyContentHandler());
//将想要解析的数据传入reader对象
reader.parse(new InputSource(new StringReader(result)));
以上是调用Sax时的核心源码,不要问为什么这么写,以现在的知识储备还无法回答,但这是官方API提供的方法,使用起来确实让人迥异万分。而 MyContentHandler 这个类需要自己重写,这个要继承DefaultHandler。
MyContentHandler详细代码:
package so.orion.XMLSax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyContentHandler extends DefaultHandler {
String name = "", sex = "", age = "", address = "";
String tagName ;
String temp ="" ;
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//System.out.println("Test—>" + this.tagName + "—" + new String (ch , start , length) );
String sb = new String(ch, start, length);
temp = temp + sb;
}
@Override
public void endDocument() throws SAXException {
System.out.println("…………..end…………..");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if( localName.equals( "student" )){
this.printAll();
}
if( tagName.equals("name")){
this.name = temp;
}else if( tagName.equals("sex")){
this.sex = temp;
}else if( tagName.equals("age")){
this.age = temp;
}else if( tagName.equals("address")){
this.address = temp;
}
}
@Override
public void startDocument() throws SAXException {
System.out.println("…………..begin…………..");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
this.tagName = localName ;
this.temp = "";
if( tagName.equals("student") ){
System.out.println("————————————–");
for( int i = 0 ; i<attributes.getLength() ; i++ ){
System.out.println( attributes.getLocalName(i) + " : "+attributes.getValue(i) );
}
}
}
public void printAll( ){
System.out.println("Name : " + this.name);
System.out.println("Sex : " + this.sex);
System.out.println("Age : " + this.age);
System.out.println("Address : " + this.address);
}
}
网上提供的简单解析过程是:startDocument->startElement->characters->endElement->endDocument
清晰点的详解图应该是:
解析器没有解析完标签时会在 startElement 和 endElement之间循环,但是我实验得出的结论是:
startDocument之后还会执行一次characters,而不知何种原因数据量非常非常小的时候characters也会自动解析多次。
说说我遇到的问题,源数据如下:
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="1240">
<name>Tony</name>
<sex>boy</sex>
<age>22</age>
<address>G301</address>
</student>
<student id="1241">
<name>John</name>
<sex>boy</sex>
<age>21</age>
<address>G302</address>
</student>
<student id="1243">
<name>Sally</name>
<sex>girl</sex>
<age>21</age>
<address>T2132</address>
</student>
<student id="1244">
<name>Tom</name>
<sex>boy</sex>
<age>23</age>
<address>G303</address>
</student>
</students>
解析时出现空数据:
网上的大神在数据处理时将成员变量在characters中做赋值判断处理,而我仿照时出现的问题怪异,于是小弟将判断处理这个代码写在 endElement里,每次标签结束后再对当前成员变量进行赋值操作,而characters无论执行多少次,我只要在成员变量声明一个String temp,在characters中执行String sb = new String(ch,start,length); temp = temp + sb ; ,在下一个startElement开始的时候再将temp赋值为空就可以了。无论中间如何执行数据都不会丢失或出现脏数据的情况,即使遇到换行符也是一样可以多次执行。
修改后的代码执行后结果:
相关文章推荐
- Android RecyclerView 完全解析
- Android中的内存泄露(一.内存泄漏的认识以及LeakCannry的基本用法)
- Android开发中混淆代码总结
- Android——DrawerLayout滑动范围的设置
- Android ListView实现通讯录的实例
- 调用Android中相机或图库选择图片并剪切
- 调用Android的相机与图库并进行剪切
- <Android学习笔记五>Android系统自带样式(android:theme)详解
- android 读取资源文件的数据
- 支付宝支付
- Android Studio 2.2 Preview 2 生成的界面问题
- Android内存泄漏解决方案(OOM)
- Volley
- android开发—Fragment中onCreateView()和onActivityCreated()的区别
- android项目开发中遇到的小而实用的代码
- android学习7#--自定义View之自定义属性
- Android开发:Service
- 转:Android中Context详解 ---- 你所不知道的Context
- 牢骚发完了,还要继续,android 圆形的过渡动画
- android5 Ripple和Reveal动效