Android的xml SAX解析的原理是逐行解析,然后调用相应的函数。
在ContentHandler接口中主要用到的函数有:
- 解析文档开始 startDocument()
- 解析文档结束 endDocument()
- 解析标签开始 startElement(String uri, String localName, String qName, Attributes atts)
- 解析标签结束 endElement(Stringuri, StringlocalName, String qName)
- 解析标签内容 characters(char[] ch, int start, int length)
由于实现接口必须重写所有方法,所以我们选择继承DefaultHandler这个类,DefaultHandler是对ContentHandler接口中所有方法
的空实现,就是所谓的适配器模式。
首先先看一下我们要解析的testxml.xml
<?xml version="1.0" encoding="UTF-8"?>
<workers>
<worker id="AQ01">
<name>Mark</name>
<sex>男</sex>
<status>经理</status>
<address>北京</address>
<money>4000</money>
</worker>
<worker id="AD02">
<name>lucy</name>
<sex>女</sex>
<status>员工</status>
<address>上海</address>
<money>1000</money>
</worker>
<worker id="AD03">
<name>lily</name>
<sex>女</sex>
<status>员工</status>
<address>北京</address>
<money>3000</money>
</worker>
</workers>
我把testxml.xml放在res/raw/testxml.xml,raw文件夹需要自己建。
(不要放在xml目录,因为我只是以字符串的方式读入)
//读取res/raw/testxml.xml并转换成字符串
InputStream inputStream = getResources().openRawResource(R.raw.testxml);
String resultStr = getString(inputStream);
System.out.println(resultStr);
这个方法是将输入的InputStream转化成字符串,网上看到的http://blog.csdn.net/barryhappy/article/details/7365271
其中
inputStreamReader = new InputStreamReader(inputStream, "utf-8");"utf-8"要用自己xml文件的编码
/**
* 输入一个inputStream返回字符串
*/
public static String getString(InputStream inputStream) {
InputStreamReader inputStreamReader = null;
try {
inputStreamReader = new InputStreamReader(inputStream, "utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BufferedReader reader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer("");
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
主Activity的完整代码XMLActivity.java,getString()方法懒得封装了,就直接丢进主代码里面
package com.example.xml;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import javax.xml.parsers.SAXParserFactory;
public class XMLActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//读取res/raw/.xml并转换成字符串
InputStream inputStream = getResources().openRawResource(R.raw.testxml);
String resultStr = getString(inputStream);
System.out.println(resultStr);
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader = factory.newSAXParser().getXMLReader();
reader.setContentHandler(new MyContentHandler());
reader.parse(new InputSource(new StringReader(resultStr)));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 输入一个inputStream返回字符串
*/
public static String getString(InputStream inputStream) {
InputStreamReader inputStreamReader = null;
try {
inputStreamReader = new InputStreamReader(inputStream, "utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BufferedReader reader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer("");
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
下面是看mars的视频教学打的MyContentHandler.java
package com.example.xml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyContentHandler extends DefaultHandler {
String hisname, address, money, sex, status;
String tagName;
int i=0;
boolean flag;
@Override
public void startDocument() throws SAXException {
System.out.println("``````````begin``````````");
}
@Override
public void endDocument() throws SAXException {
System.out.println("``````````end``````````");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
flag = true;
tagName = localName;
if(localName.equals("worker")) {
for(int i=0; i<attributes.getLength(); i++) {
System.out.println(attributes.getLocalName(i) + "=" + attributes.getValue(i));
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
flag = false;
if(localName.equals("worker")) {
this.printout();
}
}
private void printout() {
System.out.print("name: ");
System.out.println(hisname);
System.out.print("sex: ");
System.out.println(sex);
System.out.print("status: ");
System.out.println(status);
System.out.print("address: ");
System.out.println(address);
System.out.print("money: ");
System.out.println(money);
System.out.println();
}
/**
* characters并不是只执行一次,只有在startElement和endElement之间的那一次才是正确的
* 所以设置一个flag
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//System.out.println(i++);
if(flag) {
if (tagName.equals("name"))
hisname = new String(ch, start, length);
else if (tagName.equals("sex"))
sex = new String(ch, start, length);
else if (tagName.equals("status"))
status = new String(ch, start, length);
else if (tagName.equals("address"))
address = new String(ch, start, length);
else if (tagName.equals("money"))
money = new String(ch, start, length);
}
}
}
这里主要是
characters()这个方法并不是在解析每个标签中只执行一次,是个坑,
在一个标签解析结束执行endElement后,和在下一个标签解析开始之前,如果碰到"\t"、"\n"之类的characters()也会执行,
视频教学并没有提到。
找了好久才找到一片文章提到这个问题,原文http://blog.csdn.net/feng88724/article/details/7013675
我的解决方法是,既然在startElement和endElement之间执行的characters()获取的数据才是正确的,
那么设个flag,来控制characters()往变量赋值。