对xml的解析方法有多种,如sax、dom、pull,在这里我就简单介绍一下sax解析xml。
XML介绍:XML(Extensible Markup Language)即可扩展标记语言,它与HTML一样,都是SGML(标准通用标记语言)。
图解:
1、2、3部分统称为节点。
1、2部分应该称为Element,中文为元素。
3部分是TextNode文本节点。
4是属性与属性值。
SAX是一种以事件为驱动的XML API,由它定义的事件流可以指定从解析器传到专门的处理程序代码的XML结构。
事件接口
ContentHandler定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。为简化工作,SAX在DefaultHandler类中提供了这些接口的默认实现。
在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。
ContentHandler是最常用的SAX接口,我们主要掌握以下5种方法
startDocument()/endDocument():通知应用程序文档的开始或结束。
startElement()/endElement(): 通知应用程序元素的开始或结束。
characters() :当语法分析器在元素中发现文本(已经解析过的字符数据)时。
属性作为Attributes参数传递,在startElement()事件中应用
Attributes定义下列方法:
getValue(i)/getValue(qName)/getValue(uri,localName)返回第i个属性值或给定名称的属性值。
getLength()返回属性长度。
getQName(i)/getLocalName(i)/getURI(i)返回限定名(带前缀)、本地名(不带前缀)和第i个属性的名称空间URI。
第一步:
针对从XML中需要获得信息,需要对其新建一个Student类,存放相关信息。
第二步:
新建一个类继承自DefaultHandler,而DefaultHandler是实现了ContenHandler 的接口。因为该接口中没有方法体所以可直接继承它的子类DefaultHandler
在菜单中选取Source,选择Override/ImplementMethods,选取需要重写的方法。
SaxHandler.java
package com.abc.json;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
import com.abc.student.student;
public class SaxHandler extends DefaultHandler {
private List<student> students=null;
private String TAG="SaxHandler";
private student s=null;//记录当前student
private String sName=null;//自定义一个标签 通过此变量,记录前一个标签的名称
public List<student> getStudents() {
return students;
}
public void setStudents(List<student> students) {
this.students = students;
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
Log.v(TAG, "$$$$$-----startDocument----$$$$");
students = new ArrayList<student>();// 适合在此事件中触发初始化行为
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// attributes:属性、uri:命名空间、localName当前标签
super.startElement(uri, localName, qName, attributes);
Log.v(TAG, "$$$$$-----startElement----$$$$");
if ("student".equals(localName)) {
s=new student();
s.setId(attributes.getValue(0));//获取第一个属性并设置id
Log.v(TAG, "attributeName:"+attributes.getLocalName(0)+"attribute_Value:"+attributes.getValue(0));
}
sName=localName;
}
public void characters(char[] ch, int start, int length)
throws SAXException {
// 文本节点(name、age)
super.characters(ch, start, length);
Log.v(TAG, "$$$$$-----characters----$$$$");
String values=new String(ch, start, length);//通过有参构造方法将字节数组转换成字符串
if (sName.equals("name")) {
s.setName(values);
}else if (sName.equals("age")) {
s.setAge(Integer.valueOf(values));//将字符串强转为整形
}
//判空
if(!values.equals("")){
Log.v(TAG, "content"+values);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
Log.v(TAG, "$$$$$-----endElement----$$$$");
if (localName.equals("student")) {//结束标签student
students.add(s);//把一个解析好的对象加入集合中,在进行下一个解析,并将student对象与自定义标签赋值为空
s=null;
}
sName=null;
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
Log.v(TAG, "$$$$$-----endDocument----$$$$");
}
}
注:
关于要获取当前TextNode,可以使用new String(ch,start,length).trim()。
这里最好对得到的字符串使用trim()方法过滤一下,可以避免读取到的XML有空格时,因为格式不整齐,造成不必要的麻烦。对Handler中相应参数的解释:
startElement( String namespaceURI, String localNameString fullName,Attributes attribu)
namespaceURI:命名空间;
localName:标签名称,即示例中的mx;
Attributes:存放该标签的所有属性。
characters(char[] ch, int start, int length)
ch:当前读取到的TextNode(将文本字符串代表为文档层次中的结点,即文本节点)字节数组;
start:字节开始的位置,如果要读取全部,那就是从0开始;
length:当前TextNode的长度。
xml:
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id=14105244>
<name>mx</name>
<age>20</age>
</student>
<student id=14105203>
<name>wh</name>
<age>45</age>
</student>
<student id=14105231>
<name>yeb</name>
<age>46</age>
</student>
</students>
针对从 XML 中需要获得信息,需要对其新建一个 Student 类,存放相关信息。
student.java
package com.abc.student;
public class student {
private String id;
private String name;
private int age;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public student(String id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public student() {
super();
}
@Override
public String toString() {
return "student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setContentHandler(handler);
xmlReader.parse(new InputSource(is));
package com.abc.json;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import com.abc.student.student;
import android.test.AndroidTestCase;
import android.util.Log;
//创建单元测试类
public class StudentTest extends AndroidTestCase {
//必须继承AndroidTestCase才可以使用JUnit进行测试
public static final String TAG="StudentTest";
//这里有一个不成文的规定,创建的类必须以test开头
public void TestParser() throws ParserConfigurationException, SAXException, IOException {
//加载需要解析的文件。
InputStream is=this.getClass().getClassLoader().getResourceAsStream("xas.xml");
//加载自己创建的处理类对象,并通过一个SAXParserFactory来创建具体SaxParser。
SAXParserFactory spf=SAXParserFactory.newInstance();
SAXParser saxparser=spf.newSAXParser();
SaxHandler shandler=new SaxHandler();
//使用SAXParser解析xml。
saxparser.parse(is, shandler);
is.close();
List<student> sList= shandler.getStudents();
for (student student : sList) {
Log.v(TAG, student.toString());
}
}
}
最后对代码将使用JUnit进行测试