在我们做有关android项目的时候,肯定会涉及到对xml文件的解析操作。以下给大家介绍一下xml文件的解析。包括DOM、SAX、Pull以及曾经我们用到的DOM4J和JDOM:
要解析的XML文件:person.xml
<? xml version="1.0" encoding="UTF-8"? > <persons> <person id="001"> <name>zhangsan</name> <age>25</age> </person> <person id="002"> <name>lisi</name> <age>23</age> </person> </persons>
创建person实体类:
package cn.itcast.domain; public class Person { private Integer id; private String name; private Short age; public Person(){} public Person(Integer id, String name, Short age) { this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Short getAge() { return age; } public void setAge(Short age) { this.age = age; } @Override public String toString() { return "Person [age=" + age + ", id=" + id + ", name=" + name + "]"; } }
1、DOM解析XML:DOM解析是将XML文件所有加载,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件
public static List<Person> getPersons(InputStream inStream) throws Throwable{ List<Person> persons = new ArrayList<Person>(); //创建解析器工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //创建解析器 DocumentBuilder builder = factory.newDocumentBuilder(); //创建文档树模型,全部的Node都以一定的顺序包括在Document对象之内, //排列成一个树状结构,以后对XML文档的全部操作都与解析器无关 Document documnet = builder.parse(inStream); //获取根元素 Element root = documnet.getDocumentElement(); //获得根元素下的person节点列表 NodeList personNodes = root.getElementsByTagName("person"); for(int i=0 ; i < personNodes.getLength(); i++){ Person person = new Person(); //获得节点中的元素 Element personElement = (Element)personNodes.item(i); //获得person中id属性 person.setId(new Integer(personElement.getAttribute("id"))); //获得person节点下的子节点 NodeList personChilds = personElement.getChildNodes(); for(int y=0 ; y < personChilds.getLength(); y++){ if(personChilds.item(y).getNodeType()==Node.ELEMENT_NODE){//推断当前节点是否是元素类型节点 Element childElement = (Element)personChilds.item(y); if("name".equals(childElement.getNodeName())){ //获得对应元素的值 person.setName(childElement.getFirstChild().getNodeValue()); }else if("age".equals(childElement.getNodeName())){ person.setAge(new Short(childElement.getFirstChild().getNodeValue())); } } } persons.add(person); } return persons; }
2、SAX解析XML:顺序读取XML文件,不须要一次所有装载整个文件,因为移动设备的内存资源有限。SAX的顺序读取方式更适合移动开发
public List<Person> getPersons(InputStream inStream) throws Throwable{ //创建SAXParserFactory SAXParserFactory factory = SAXParserFactory.newInstance(); //创建SAX解析器 SAXParser parser = factory.newSAXParser(); //创建XML解析处理器 PersonParser personParser = new PersonParser(); //将XML解析处理器分配给解析器,对文档进行解析,将每一个事件发送给处理器 parser.parse(inStream, personParser); inStream.close(); return personParser.getPersons(); } //定义解析处理器 private final class PersonParser extends DefaultHandler{ private List<Person> persons = null;//将解析的数据放在List集合中 private String tag = null;//定义一个全局变量的标签名称 private Person person = null; public List<Person> getPersons() { return persons; } //解析Document @Override public void startDocument() throws SAXException { //解析<persons>部分 persons = new ArrayList<Person>(); } @Override public void endDocument() throws SAXException { System.out.println("end parse xml"); } /** * 解析Element * namespaceURI 命名空间 * localName 不带前缀部分<person id="001">--->person * qName 带前缀部分<abc:person id="001">---->abc:worker * attributes 属性集合 <abc:person id="001">---->id="001".... */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //解析<person id="001">部分 if("person".equals(localName)){ person = new Person(); person.setId(new Integer(attributes.getValue(0))); } tag = localName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { //解析当中的文本<name>zhangsan</name>-->zhangsan if(tag!=null){ String data = new String(ch, start, length);//获取文本节点的数据 if("name".equals(tag)){ person.setName(data); }else if("age".equals(tag)){ person.setAge(new Short(data)); } } } //解析结束元素 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("person".equals(localName)){ persons.add(person); person = null; } tag = null; } }
3、pull解析XML:pull解析和SAX解析非常相似。都是轻量级的解析,在android内核中已经嵌入了pull。所以我们不须要再加入第三方jar包来支持pull
/** * 使用pull解析XML文档 * @param inStream * @return * @throws Throwable */ public static List<Person> getPersons(InputStream inStream) throws Throwable{ List<Person> persons = null; Person person = null; XmlPullParser parser = Xml.newPullParser(); parser.setInput(inStream, "UTF-8"); int eventType = parser.getEventType();//产生第一个事件 while(eventType!=XmlPullParser.END_DOCUMENT){//仅仅要不是文档结束事件 switch (eventType) { case XmlPullParser.START_DOCUMENT://推断当前事件是否是文档開始事件 persons = new ArrayList<Person>();//初始化Person集合 break; case XmlPullParser.START_TAG://推断当前事件是否是标签元素開始事件 String name = parser.getName();//获取解析器当前指向的元素的名称 if("person".equals(name)){ person = new Person(); //得到对应的标签的属性值 person.setId(new Integer(parser.getAttributeValue(0))); } if(person!=null){ if("name".equals(name)){ //获取解析器当前指向元素的下一个文本节点的值 person.setName(parser.nextText()); } if("age".equals(name)){ person.setAge(new Short(parser.nextText())); } } break; case XmlPullParser.END_TAG://推断当前事件是否是标签元素结束事件 if("person".equals(parser.getName())){ persons.add(person); person = null; } break; } //进入下一元素并触发对应事件 eventType = parser.next(); } return persons; }
採用pull解析器创建一个xml文档:
/** * 使用pull解析器创建一个xml文档 * @param persons * @param writer * @throws Throwable */ public static void save(List<Person> persons, Writer writer) throws Throwable{ XmlSerializer serializer = Xml.newSerializer(); serializer.setOutput(writer); serializer.startDocument("UTF-8", true); serializer.startTag(null, "persons"); for(Person person : persons){ serializer.startTag(null, "person"); serializer.attribute(null, "id", person.getId().toString()); serializer.startTag(null, "name"); serializer.text(person.getName()); serializer.endTag(null, "name"); serializer.startTag(null, "age"); serializer.text(person.getAge().toString()); serializer.endTag(null, "age"); serializer.endTag(null, "person"); } serializer.endTag(null, "persons"); serializer.endDocument(); writer.flush(); writer.close(); }
在android项目中通过Junit对各方法进行測试:
注意在使用junit的时候,须要在AndroidMainifest.xml中增加:
<uses-library android:name="android.test.runner" /> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.xin.activity" android:label="Tests for My App" />
编写我们的java測试类:
public class PersonServiceTest extends AndroidTestCase { private static final String TAG = "PersonServiceTest"; public void testSAXGetPersons() throws Throwable{ SAXPersonService service = new SAXPersonService(); InputStream inStream = getClass().getClassLoader().getResourceAsStream("person.xml"); List<Person> persons = service.getPersons(inStream); for(Person person : persons){ Log.i(TAG, person.toString()); } } public void testDomGetPersons() throws Throwable{ InputStream inStream = getClass().getClassLoader().getResourceAsStream("person.xml"); List<Person> persons = DOMPersonService.getPersons(inStream); for(Person person : persons){ Log.i(TAG, person.toString()); } } public void testPullGetPersons() throws Throwable{ InputStream inStream = getClass().getClassLoader().getResourceAsStream("person.xml"); List<Person> persons = PULLPersonService.getPersons(inStream); for(Person person : persons){ Log.i(TAG, person.toString()); } } }
执行输出就可以得到我们想要的结果!
几种方法比較:
SAX:一行一行读取。效率高,读取到对应须要的数据后不再往下操作,操作复杂,适合移动设备
DOM:操作简单,一開始载入一个DOM树,当XML文件相对照计较大的时候影响效率,速度慢
* Pull解析和Sax解析不一样的地方有
* (1)pull读取xml文件后触发对应的事件调用方法返回的是数字
* (2)pull能够在程序中控制想解析到哪里就能够停止解析
事实上pull解析xml不仅适用于android,在我们的javase中也能够使用pull解析器来解析xml文件,只是须要导入对应的jar包:
kxml2-2.3.0.jar,下载地址:http://kxml.sourceforge.net/
xmlpull_1_1_3_4c.jar 下载地址:http://www.xmlpull.org/
曾经我们还使用了DOM4J和JDOM来解析xml。能够參见我的博客,只是须要导入对应的支持jar包:
DOM4J解析XML:http://blog.csdn.net/harderxin/article/details/7285770
JDOM解析XML:http://blog.csdn.net/harderxin/article/details/7285754