XML解析有三种方式,这里来总结一下
*************************SAX*************************
首先是SAX方式,这种方式是边加载边解析
关键的一个类是DefaultHandler,我们通过集成这个类,Override一些关键的方法,从而解析XML文件
主要的方法有
@Override public void startDocument() throws SAXException { list = new ArrayList<Person>(); Log.i(tag,"startDocument()"); }
这个方法是在开始解析文档的时候调用,通常做一下初始化的工作,然后就绪执行startElement()方法
@Override public void startElement(String uri,String localName,String qName,Attributes attributes) throws SAXException { ...... preTag = localName; }
我在startElement()方法里面解析XML标签,其中localName是当前标签的名字,attributes是存储了标签属性的数组,我们通过if语句判断是否我们需要的标签,然后提取需要的属性信息来构造Bean就可以了
这里我们使用一个preTag全局变量来存储当前标签,便于character方法的使用
然后会接着执行character()方法,我们在这个方法里面提取文本信息
@Override public void characters(char[] ch,int start,int length) throws SAXException { String content = new String(ch,start,length); ....... }
这里构造出的content就是文本信息了,但是我怎么知道,这个那个标签里面的文本信息,这时就要使用到preTag,来判断是那个标签
@Override public void endElement(String uri,String qName) throws SAXException { ....... Log.i(tag,localName+"***end element***"); preTag = null; }
这里我们有获得了localName,也就是当前标签的名字
并且我们有一个关键的操作,就是preTag=null的设置
因为xml文件里面,空白区域也被当成了节点,所以我们如果不设置pretag为空,那么preTag记录的就是上一个标签的名字,当我们解析到空白节点时,进入character()方法,就可能把远的preTag所对应的文本覆盖成空
@Override public void endDocument() throws SAXException { Log.i(tag,"endDocument()"); }
继承好DefaultHandler类以后,我就要使用
InputStream is = PersonServiceTest.class.getClassLoader().getResourceAsStream("person.xml"); if(is!=null){ SAXForHandler s = new SAXForHandler(); SAXParserFactory pf = SAXParserFactory.newInstance(); SAXParser sp = pf.newSAXParser(); sp.parse(is,s); for(Person person:s.list){ Log.i(Tag,person.toString()); } }
使用方法很简单,首先创建一个SAX工程,然后利用工程生成一个解析器
把xml数据流,和Handler对象传入解析器就可以了
*************************DOM*************************
dom解析方式是先加载整个xml文件再解析,这样的好处是,我们知道了DOM树的结构,和节点之间的关系,不利之处是要加载整个文件,解析速度慢
解析方式如下,首先创建一个DOMbulider工程,然后生产一个DOMbulider,把xml数据流传入DOMbulider.parse(),就可以生成一个DOMCUMENT对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(inStream);
下面的解析过程就比较难说清楚了,首先是获取文件根节点
Element root = document.getDocumentElement();
然后根据文件根节点,获取所有Node
NodeList personNodes = root.getElementsByTagName("person");
这里要说明一下node跟Elment,我们主要使用element来获取标签的相关信息,不过首先我们要使用Node转换成Element
我们通过一个循环,来遍历所有的Person,用node.item()来获取,对于每一个node,我们在强制转换成Element
for(int i=0;i<personNodes.getLength();i++){ Element personElement = (Element) personNodes.item(i); ..... }
有了element对象,我就可以获取它的属性
int id = new Integer(personElement.getAttribute("id"));
接着像根节点一样,获取该element的所有子节点
NodeList childNodes = personElement.getChildNodes(); for(int y=0;y<childNodes.getLength();y++){ ..... }不断地按照这个方式,就能完整构造出bean对象
*************************PULL*************************
PULL方法,可以说结合了上面两种方法解析便利上的优点,并且它表示通过工厂创建的,而是直接创建,但是接下来把xml流传进去解析,也是一样的步骤
XmlPullParser pullParser = Xml.newPullParser(); pullParser.setInput(inStream,"UTF-8");
下面的解析全都围绕着pullParser这个对象进行了
首先一个方法是getEventType()获取当前节点的类型,注意每次pullParser都表示当前正在解析的节点,只有调用它的next()方法,才会移到下一个节点,类似cursor
判断节点类型后,不是END_DOCUEMNT,我们就一直解析(next())
接着几个属性就是XmlPullParser.START_DOCUMENT,XmlPullParser.START_TAG,XmlPullParser.END_TAG
根据不同类型解析就可以了
pullParser.getName()获得标签名字
pullParser.getAttributeValue(0)获得标签属性
pullParser.nextText()获得标签文本
int event = pullParser.getEventType(); while(event!=XmlPullParser.END_DOCUMENT){ switch(event){ case XmlPullParser.START_DOCUMENT: persons = new ArrayList<Person>(); break; case XmlPullParser.START_TAG: if("person".equals(pullParser.getName())){ int id = new Integer(pullParser.getAttributeValue(0)); person = new Person(); person.setId(id); } if(person!=null){ if("name".equals(pullParser.getName())){ person.setName(pullParser.getAttributeValue(0)); } if("age".equals(pullParser.getName())){ person.setAge(new Short(pullParser.nextText())); } if("ddd".equals(pullParser.getName())){ person.setDdd(pullParser.nextText()); } } break; case XmlPullParser.END_TAG: if("person".equals(pullParser.getName())){ persons.add(person); person = null; } } event = pullParser.next(); }
说过XML的解析,我顺便说一下xml文件的构造,这种构造方法,跟pull解析的方式很类似,就是刚好反过来
然后startDocument()方法,就可以开始构造文件根节点
然后startTag()就可以设置一个标签
text()就可以设置文本
endTag()就可以闭合标签
其中startTag相互嵌套,就可以构成树状结构
最好endDocument()就可以关闭root了
XmlSerializer serializer = Xml.newSerializer(); serializer.setOutput(outStream,"UTF-8"); serializer.startDocument("UTF-8",true); serializer.startTag(null,"persons"); for (Person person : persons) { serializer.startTag(null,"person"); serializer.attribute(null,"id","1"); serializer.startTag(null,"name"); serializer.text("zhangsan"); serializer.endTag(null,"name"); } serializer.endTag(null,"persons"); serializer.endDocument(); outStream.flush(); outStream.close();