1.SAX
SAX(simple API for XML),一种基于事件驱动模型的XML解析标准接口。
工作原理:
SAX简单地说就是对XML文档进行顺序扫描,当扫描到文档的开始与结束 , 元素(element)的开始与结束时,就会触发相应的事件处理 函数,由事件处理函数做相应的动作,处理完后继续扫描,直到文档结束,则解析完毕。
实现步骤:
(1)SAXParserFactory fa = SAXParserFactory.newInstance(); //获得SAX解析工厂对象
(2)XMLReader reader = fa.newSAXParser().getXMLReader(); //通过SAX解析工厂对象得到一个XMLReader
(3)reader.setContentHandler(new MySAXContentHandler()); //注册ContentHandler内容解析监听对象
(4)reader.parse(new InputSource(new StringReader(xmlStr))); //开始解析XML文件
步骤说明:
对于每个XMLReader 可以注册四种监听接口 ,分别为 ContentHandler,DTDHandler,ErrorHandler以及EntityResolver,其中 ContentHandler 为最主要的,也是最经常使用的接口。
调用parse方法解析XML文件,需要的是一个InputSource对象,而InputSource对象又需要一个Reader字符流对象,所以可以通过
new InputSource(new StringReader(xmlStr)) 的方式,来生成一个InputSource对象,供XMLReader对象解析所用。
这里的StringReader是以提供的String 数据所创建一个字符流。
ContentHandler:
在XMLReader解析XML文件的时候,会触发所注册的ContentHandler内的方法,关键方法如下:
public void startDocument() //开始解析文档
public void endDocument() //结束解析文档
public void startElement() //开始解析元素
public void endElement() //结束解析元素
public void characters() //读取元素的内容
下面以一个实例来说明:
首先是需要解析的XML文件:students.xml
<?xml version="1.0" encoding="utf-8"?>
<studentlist>
<student attr1="ar1" attr2="ar2">
<id>1</id>
<name>jack</name>
<age>18</age>
</student>
<student attr1="ar1" attr2="ar2">
<id>2</id>
<name>tom</name>
<age>20</age>
</student>
</studentlist>
把这个文件放在Android工程目录下的res/raw文件夹内,然后调用getResource().openRawResource(R.id.students)得到一个输入流,将其读取到程序中来。代码如下:
/**
* 以字符流的形式从res/raw文件夹中读取students.xml文件
*/
public void getXMLFile2String()
{
StringBuffer buffer = new StringBuffer();
BufferedReader bufferReader = null;
try {
String line =null;
bufferReader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.students)));
while((line=bufferReader.readLine())!=null)
{
buffer.append(line);
}
xmlStr=buffer.toString();//读取完毕后赋值给
} catch (Exception e) {
e.printStackTrace();
}finally{
if(bufferReader!=null)
{
try {
bufferReader.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
再定义一个对应的Student持久化类,代码如下:
public class Student {
private String id;
private String name;
private String age;
public Student(){}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
实现自己的ContentHandler:
可以通过实现ContentHandler接口来定义自己的ContentHandler,不过这样做就会有很多用不上的方法被空实现出来,所以这里采用继承 org.xml.sax.helpers.DefaultHandler类,把需要用到的方法实现出来即可,代码如下:
public class MySAXContentHandler extends DefaultHandler{
private String curentTag; //当前读取到的标签
private List<Student> stus = new ArrayList<Student>();
private Student stu;
@Override
public void startDocument() throws SAXException {
System.out.println("start----");
}
@Override
public void endDocument() throws SAXException {
System.out.println("end-----");
printAll();
}
/**
* url 标签的命名空间
* localName 不带前缀的标签名
* qName 带前缀的标签名
* attributes 标签的属性
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
curentTag=localName;
if(localName.equals("student")){
stu = new Student();
for(int i=0;i<attributes.getLength();i++)//打印所有的属性
{
System.out.println(attributes.getLocalName(i)+" is :"+attributes.getValue(i));
}
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(localName.equals("student")){
stus.add(stu);
}
}
/**
* ch 标签的内容所对应的字符数组
* start 开始位置
* length 长度
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(curentTag.equals("name")){
stu.setName(new String(ch,start,length));
}else if(curentTag.equals("id")){
stu.setId(new String(ch,start,length));
}else if(curentTag.equals("age")){
stu.setAge(new String(ch,start,length));
}
}
//打印所有的学生信息
public void printAll()
{
for(Student s:stus)
{
System.out.println(s.getId());
System.out.println(s.getName());
System.out.println(s.getAge());
}
}
}
这里需要说明一下,使用自定义的ContentHandler解析XML文件的时候,需要提供一个String curentTag 对象来记录当前正在解析的是哪一个标签,通过在startElement方法中实时的更新,而在characters方法中通过对curentTag 的判断来实行不同的操作。
总结:使用SAX来解析XML文件,实际上是一个边读边解析的过程,当文件读取完毕后,也就解析完毕。而其中ContentHandler是最主要的解析监听接口,它以标签为基本单位,在解析时候触发相应方法,在方法中会传入相应的参数,以对不同的标签进行不同的操作。
2.DOM
DOM(Document Object Model),是一种基于文档对象模型的解析XML标准接口。
工作原理:
DOM解析XML文件时,会将XML文件的所有内容读取到内存中,然后允许你使用DOM API 操作XML 树。也就是说,DOM 会把XML以树的形式读取到内存中,然后在通过相应的API 来操作这个XML树,从而达到解析XML文件的目的。
一般不建议在手机上采用DOM来解析XML,因为这样会占用比较多的内存。
ps:DOM是由w3c定义的一个解析XML的标准,一些第三方类库在此基础上扩展并优化了解析的过程,其中dom4j和jdom都是比较优秀的第三方类库。
3.JSON(JavaScript Object Natation),JSON数据是一系列键值对的集合,在网络传输中被广泛应用。
json的结构:
{"name":"Jack", "address": { "city":"Shanghai", "street":"Pufa Road" }}
说明:一对{ }代表一个json对象。
“key”:“value”, 代表一个键值对 。
而一个key又可以指向一个json对象。
JSON数组:
多个json对象形成的数组,例如:
[ {"name":"Jack","age":1"} , {"name":"tom","age":18} ]
JSON的解析:
Android3.0提供了JsonReader这样一个类,其本质其实也是Gson,也就是Google一个开源的用于解析JSON的类库。所以为了使用这个类库来解析JSON,必须添加gson-1.6.jar包。(可到Google网站下载)
JSON的解析又可以分两个方向:
一种是类似SAX的事件监听模式,如下;
private String jsonArray = "[ {\"name\":\"Jack\",\"age\":12} , {\"name\":\"tom\",\"age\":18} ]";
public static void parseJSON(String jsonArray)
{
try {
JsonReader reader = new JsonReader(new StringReader(jsonArray));
reader.beginArray();
while(reader.hasNext())
{
reader.beginObject();
while(reader.hasNext())
{
String keyName = reader.nextName();
if(keyName.equals("name")){
System.out.println("name is "+reader.nextString());
}else if(keyName.equals("age"))
{
System.out.println("age is "+reader.nextInt());
}
}
reader.endObject();//
}
reader.endArray();//
} catch (Exception e) {
e.printStackTrace();
}
}
另外一种是可以直接即将JSON转换为持久化类,如下:
private String jsonArray = "[ {\"name\":\"Jack\",\"age\":12} , {\"name\":\"tom\",\"age\":18} ]";
public static void parseJSONArray2ObjecList(String jsonArray)
{
Type listType = new TypeToken<LinkedList<User>>(){}.getType();//反射得到一个Type对象
LinkedList<User> list = new Gson().fromJson(jsonArray, listType);
Iterator<User> iterator = list.iterator();
while(iterator.hasNext())
{
User user = (User)iterator.next();
System.out.println("name is " + user.getName());
System.out.println("age is" + user.getAge());
}
}
对应的持久化类:
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
新建一个JSON:
public static void newJSON()
{
List<User> users = new ArrayList<User>();
User user1 = new User();
user1.setAge(25);
user1.setName("tonmy");
users.add(user1);
User user2 = new User();
user2.setAge(45);
user2.setName("peter");
users.add(user2);
Gson gson = new Gson();
String jsonStr = gson.toJson(users);
System.out.println(jsonStr);
}
打印出来的字符串为:[ { "name":"tonmy" , "age":25 } , { "name":"peter","age":45 } ]
总结:JSON其实就是满足特定规则的一种数据形式,它提供了一个方便快捷的数据交换途径,在与JavaScript的交互中有良好的表现,因为JavaScript可直接识别出JSON而不需要在做其他的出来,这点相对于XML还是比较方便的。但对一些拥有复杂结构的数据,使用JSON就不是那么适合。
SAX(simple API for XML),一种基于事件驱动模型的XML解析标准接口。
工作原理:
SAX简单地说就是对XML文档进行顺序扫描,当扫描到文档的开始与结束 , 元素(element)的开始与结束时,就会触发相应的事件处理 函数,由事件处理函数做相应的动作,处理完后继续扫描,直到文档结束,则解析完毕。
实现步骤:
(1)SAXParserFactory fa = SAXParserFactory.newInstance(); //获得SAX解析工厂对象
(2)XMLReader reader = fa.newSAXParser().getXMLReader(); //通过SAX解析工厂对象得到一个XMLReader
(3)reader.setContentHandler(new MySAXContentHandler()); //注册ContentHandler内容解析监听对象
(4)reader.parse(new InputSource(new StringReader(xmlStr))); //开始解析XML文件
步骤说明:
对于每个XMLReader 可以注册四种监听接口 ,分别为 ContentHandler,DTDHandler,ErrorHandler以及EntityResolver,其中 ContentHandler 为最主要的,也是最经常使用的接口。
调用parse方法解析XML文件,需要的是一个InputSource对象,而InputSource对象又需要一个Reader字符流对象,所以可以通过
new InputSource(new StringReader(xmlStr)) 的方式,来生成一个InputSource对象,供XMLReader对象解析所用。
这里的StringReader是以提供的String 数据所创建一个字符流。
ContentHandler:
在XMLReader解析XML文件的时候,会触发所注册的ContentHandler内的方法,关键方法如下:
public void startDocument() //开始解析文档
public void endDocument() //结束解析文档
public void startElement() //开始解析元素
public void endElement() //结束解析元素
public void characters() //读取元素的内容
下面以一个实例来说明:
首先是需要解析的XML文件:students.xml
<?xml version="1.0" encoding="utf-8"?>
<studentlist>
<student attr1="ar1" attr2="ar2">
<id>1</id>
<name>jack</name>
<age>18</age>
</student>
<student attr1="ar1" attr2="ar2">
<id>2</id>
<name>tom</name>
<age>20</age>
</student>
</studentlist>
把这个文件放在Android工程目录下的res/raw文件夹内,然后调用getResource().openRawResource(R.id.students)得到一个输入流,将其读取到程序中来。代码如下:
/**
* 以字符流的形式从res/raw文件夹中读取students.xml文件
*/
public void getXMLFile2String()
{
StringBuffer buffer = new StringBuffer();
BufferedReader bufferReader = null;
try {
String line =null;
bufferReader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.students)));
while((line=bufferReader.readLine())!=null)
{
buffer.append(line);
}
xmlStr=buffer.toString();//读取完毕后赋值给
} catch (Exception e) {
e.printStackTrace();
}finally{
if(bufferReader!=null)
{
try {
bufferReader.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
再定义一个对应的Student持久化类,代码如下:
public class Student {
private String id;
private String name;
private String age;
public Student(){}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
实现自己的ContentHandler:
可以通过实现ContentHandler接口来定义自己的ContentHandler,不过这样做就会有很多用不上的方法被空实现出来,所以这里采用继承 org.xml.sax.helpers.DefaultHandler类,把需要用到的方法实现出来即可,代码如下:
public class MySAXContentHandler extends DefaultHandler{
private String curentTag; //当前读取到的标签
private List<Student> stus = new ArrayList<Student>();
private Student stu;
@Override
public void startDocument() throws SAXException {
System.out.println("start----");
}
@Override
public void endDocument() throws SAXException {
System.out.println("end-----");
printAll();
}
/**
* url 标签的命名空间
* localName 不带前缀的标签名
* qName 带前缀的标签名
* attributes 标签的属性
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
curentTag=localName;
if(localName.equals("student")){
stu = new Student();
for(int i=0;i<attributes.getLength();i++)//打印所有的属性
{
System.out.println(attributes.getLocalName(i)+" is :"+attributes.getValue(i));
}
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(localName.equals("student")){
stus.add(stu);
}
}
/**
* ch 标签的内容所对应的字符数组
* start 开始位置
* length 长度
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(curentTag.equals("name")){
stu.setName(new String(ch,start,length));
}else if(curentTag.equals("id")){
stu.setId(new String(ch,start,length));
}else if(curentTag.equals("age")){
stu.setAge(new String(ch,start,length));
}
}
//打印所有的学生信息
public void printAll()
{
for(Student s:stus)
{
System.out.println(s.getId());
System.out.println(s.getName());
System.out.println(s.getAge());
}
}
}
这里需要说明一下,使用自定义的ContentHandler解析XML文件的时候,需要提供一个String curentTag 对象来记录当前正在解析的是哪一个标签,通过在startElement方法中实时的更新,而在characters方法中通过对curentTag 的判断来实行不同的操作。
总结:使用SAX来解析XML文件,实际上是一个边读边解析的过程,当文件读取完毕后,也就解析完毕。而其中ContentHandler是最主要的解析监听接口,它以标签为基本单位,在解析时候触发相应方法,在方法中会传入相应的参数,以对不同的标签进行不同的操作。
2.DOM
DOM(Document Object Model),是一种基于文档对象模型的解析XML标准接口。
工作原理:
DOM解析XML文件时,会将XML文件的所有内容读取到内存中,然后允许你使用DOM API 操作XML 树。也就是说,DOM 会把XML以树的形式读取到内存中,然后在通过相应的API 来操作这个XML树,从而达到解析XML文件的目的。
一般不建议在手机上采用DOM来解析XML,因为这样会占用比较多的内存。
ps:DOM是由w3c定义的一个解析XML的标准,一些第三方类库在此基础上扩展并优化了解析的过程,其中dom4j和jdom都是比较优秀的第三方类库。
3.JSON(JavaScript Object Natation),JSON数据是一系列键值对的集合,在网络传输中被广泛应用。
json的结构:
{"name":"Jack", "address": { "city":"Shanghai", "street":"Pufa Road" }}
说明:一对{ }代表一个json对象。
“key”:“value”, 代表一个键值对 。
而一个key又可以指向一个json对象。
JSON数组:
多个json对象形成的数组,例如:
[ {"name":"Jack","age":1"} , {"name":"tom","age":18} ]
JSON的解析:
Android3.0提供了JsonReader这样一个类,其本质其实也是Gson,也就是Google一个开源的用于解析JSON的类库。所以为了使用这个类库来解析JSON,必须添加gson-1.6.jar包。(可到Google网站下载)
JSON的解析又可以分两个方向:
一种是类似SAX的事件监听模式,如下;
private String jsonArray = "[ {\"name\":\"Jack\",\"age\":12} , {\"name\":\"tom\",\"age\":18} ]";
public static void parseJSON(String jsonArray)
{
try {
JsonReader reader = new JsonReader(new StringReader(jsonArray));
reader.beginArray();
while(reader.hasNext())
{
reader.beginObject();
while(reader.hasNext())
{
String keyName = reader.nextName();
if(keyName.equals("name")){
System.out.println("name is "+reader.nextString());
}else if(keyName.equals("age"))
{
System.out.println("age is "+reader.nextInt());
}
}
reader.endObject();//
}
reader.endArray();//
} catch (Exception e) {
e.printStackTrace();
}
}
另外一种是可以直接即将JSON转换为持久化类,如下:
private String jsonArray = "[ {\"name\":\"Jack\",\"age\":12} , {\"name\":\"tom\",\"age\":18} ]";
public static void parseJSONArray2ObjecList(String jsonArray)
{
Type listType = new TypeToken<LinkedList<User>>(){}.getType();//反射得到一个Type对象
LinkedList<User> list = new Gson().fromJson(jsonArray, listType);
Iterator<User> iterator = list.iterator();
while(iterator.hasNext())
{
User user = (User)iterator.next();
System.out.println("name is " + user.getName());
System.out.println("age is" + user.getAge());
}
}
对应的持久化类:
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
新建一个JSON:
public static void newJSON()
{
List<User> users = new ArrayList<User>();
User user1 = new User();
user1.setAge(25);
user1.setName("tonmy");
users.add(user1);
User user2 = new User();
user2.setAge(45);
user2.setName("peter");
users.add(user2);
Gson gson = new Gson();
String jsonStr = gson.toJson(users);
System.out.println(jsonStr);
}
打印出来的字符串为:[ { "name":"tonmy" , "age":25 } , { "name":"peter","age":45 } ]
总结:JSON其实就是满足特定规则的一种数据形式,它提供了一个方便快捷的数据交换途径,在与JavaScript的交互中有良好的表现,因为JavaScript可直接识别出JSON而不需要在做其他的出来,这点相对于XML还是比较方便的。但对一些拥有复杂结构的数据,使用JSON就不是那么适合。