zoukankan      html  css  js  c++  java
  • Android之旅十四 android中的xml文件解析

       在我们做有关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

  • 相关阅读:
    Python统计词频的几种方式
    GO语言系列之 基本数据类型和操作符
    GO语言系列之 初识go语言
    Python实现聚类算法AP
    最大似然估计
    Breastcancer社区评论下载
    数据可视化之pyecharts
    Requests库
    nginx内置变量
    Tomcat内部结构、工作原理、工作模式和运行模式
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5373326.html
Copyright © 2011-2022 走看看