在我们做有关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 + "]"; } }
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