这些一直以来比较迷迷糊糊,今天翻阅网上翻阅了相关博文和书籍,大致整理了一下(还是相对比较浅的,以后有了新的理解之后在继续深入)
例如:
待解析文件Classmate.xml <class> <student> <id>1</id> <name>Qbin</name> <sex>male</sex> </student> <student> <id>2</id> <name>Qmm</name> <sex>female</sex> </student> <student> <id>3</id> <name>Cmy</name> <sex>male</sex> </student> </class>
SAX解析方法:
public class Main{ ....... parseXMLWithSAX(xmldata); //调用SAX解析方法 ....... private void parseXMLWithSAX(String xmldata){ try{ SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); //获得SAX解析器对象 XMLReader xmlReader = parser.getXMLReader(); //获得XMLReader对象 ContentHandler handler = new ContentHandler(); xmlReader.setContentHandler(handler); //将handler模版设置xmlReader中 xmlReader.parse(new InputSource(new StringReader(xmldata))) //开始解析 } catch(Exception e){ e.printStackTrace(); } } ....... } public class ContentHandler extends DefaultHandler { private String nodeName; private StringBuilder id; private StringBuilder name; private StringBuilder sex; @Override public void startDocument() throws SAXException { //在XML开始解析是调用 id = new StringBuilder; name = new StringBuilder; sex = new StringBuilder; } @Override public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException { /*在解析某个节点时调用 * 相当于一个循环,从根节点开始,每读到一个新的节点, * 便执行一次这个方法,然后把该节点里的所有属性都存到Attributes里, * * @param uri xml文档的uri地址,这里直接传入的是inputStream,所以uri为空 * @param localName 本地名,一般和qName相同 * @param qName 节点名 * @param attributes 当前节点下的所有属性都存放到该参数里了 * @throws SAXException 包含任何sax解析的异常 */ nodeName = localName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { /*在解析节点中具体内容时调用 * 该方法里存放的是每个节点里的文本内容,文本内容存到ch数组里, * 在此根据判断当前节点名,将内容添加到哪个StringBuilder中 * * @param ch 用来存放每个节点里的文本内容 * @param start 文本内容是从哪开始的,如果文本内容前面有1个空格,则start为1,如果没有空格,则start为0 * @param length ch数组的长度,包含空格 * @throws SAXException 各种sax解析异常 */ if("id".equals(nodeName)){ id.append(ch,start,length); }else if("name".equals(nodeName)){ name.append(ch,start,length); }else if("sex".equals(nodeName)){ sex.append(ch,start,length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { /*每个节点读取完毕时调用 * * @param uri xml文档的uri地址,也可以为url,这里直接传入的是inputStream,所以uri为空 * @param localName 本地名,一般和qName相同 * @param qName 节点名 * @throws SAXException 各种sax解析异常 */ if("student".equals(localName)){ Log.d( "SAX" , "id =" + id.toString().trim()); Log.d( "SAX" , "name=" + name.toString().trim()); Log.d( "SAX" , "sex=" + sex.toString().trim()); //trim()方法,除去字符串两端不可见字符 id.setLength(0); name.setLength(0); sex.setLength(0); //清空StringBuilder,以免影响下次内容读取 } } @Override public void endDocument() throws SAXException { //在完成整个XML解析时调用 super.endDocument(); } }
PULL解析方法:
public class Main{ ....... parseXMLWithPull(xmldata); //调用PULL解析方法 ....... private void parseXMLWithPull(String xmldata){ try{ XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); //获得PULL解析器对象 parser.setInput(new StringReader(xmldata)); // 将XML数据放入解析器 int eventType = parser.getEventType(); //获得当前节点 String id = ""; String name = ""; String sex = ""; while(eventType != paser.END_DOCUMENT){ String nodeName = parser.getName(); switch(eventType){ //开始解析某个节点 case parser.START_TAG:{ if("id".equals(nodeName)){ id = parser.nextText(); //用nextText()方法获得节点内具体内容 }else if("name"equals(nodeName)){ name = parser.nextText(); }else if("sex".equals(nodeName)){ sex = parser.nextText(); } break; } //完成解析某个节点 case parser.END_TAG:{ if("student".equals(nodeName)){ Log.d( "PULL" , "id =" + id); Log.d( "PULL" , "name=" + name); Log.d( "PULL" , "sex=" + sex); } break; } default: break; } eventType = parser.next(); //用next()方法获取下一个解析事件 }catch(Exception e){ e.printStackTrace(); } } }
总结:
共同点:PULL解析和SAX解析都是事件驱动(事件驱动是基于回调机制对程序运行方法),DOM是文档驱动
SAX解析(优点):不需要提前把文档读入内存(即占用内存小,相对于DOM解析);解析速度快;
(缺点):一旦开始解析,就停不下来,直到解析完整个XML文档。
PULL解析(优点):类似于SAX,并且PULL解析能控制当什么时候跳出解析(即用break跳出while)