对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>
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进行测试