解析速度快,占用内存少,采用事件驱动,即不需要加载完整个文档,而是按内容顺序解析文档,在此过程中,其会判断当前读到的内容是否符合XML语法定义

AD:


Android平台上可以使用SimpleAPIforXML(SAX),DocumentObjectModel(DOM)和Android附带的pull解析器解析XML文件

众所周知,,DOM解析方式很耗内存,优先使用SAX或者pull

SAX:

解析速度快,占用内存少,采用事件驱动,即不需要加载完整个文档,而是按内容顺序解析文档,在此过程中,其会判断当前读到的内容是否符合XML语法定义,如果符合就会触发事件,所谓事件,其实就是一些callback方法,具体方法含义比较简单,看文档即可,定义在DefaultHandler接口中(SAX已内置到JDK5.0中)

待解析xml文件musics.xml:

 
     
  1. "1.0"encoding="utf-8"?>

  2. "1">

  3. 黑色幽默

  4. Jay

  5. 2000

  6. "2">

  7. 爱在西元前

  8. 范特西

  9. 2001

  10. "3">

  11. 回到过去

  12. 八度空间

  13. 2002

  14. "4">

  15. 东风破

  16. 叶惠美

  17. 2003

  18. "5">

  19. 七里香

  20. 七里香

  21. 2004

  22. "6">

  23. 一路向北

  24. 十一月的萧邦

  25. 2005

实体类MusicEntity就不贴了,四个属性,上面的xml中也可以看出.

实现了DefaultHandler接口的SaxHandler:

 
     
  1. publicclassSaxHandlerextendsDefaultHandler{

  2. privatestaticfinalStringTAG="lanyan";

  3. privateListmusics;

  4. privateMusicEntitymusic;

  5. //缓存上一次的标签名

  6. privateStringpreTag;

  7. @Override

  8. publicvoidstartDocument()throwsSAXException{

  9. musics=newArrayList();

  10. }

  11. @Override

  12. publicvoidstartElement(Stringuri,StringlocalName,StringqName,

  13. Attributesattributes)throwsSAXException{

  14. if("music".equals(localName)){

  15. music=newMusicEntity();

  16. music.setId(Integer.parseInt(attributes.getValue("id")));

  17. }

  18. preTag=localName;

  19. }

  20. /**

  21. *解析到文档中字符内容时调用

  22. *所以一般网络中传输的xml,其父节点与子节点之间是紧挨在一起的,基本上就是一行,看起来很混乱,其实是为了避免解析时无必要的调用

  23. *这里仅是测试,故忽略这个因素

  24. */

  25. @Override

  26. publicvoidcharacters(char[]ch,intstart,intlength)

  27. throwsSAXException{

  28. if(null!=music){

  29. Stringstr=newString(ch,start,length);

  30. if("name".equals(preTag)){

  31. music.setName(str);

  32. }elseif("albumName".equals(preTag)){

  33. music.setAlbumName(str);

  34. }elseif("year".equals(preTag)){

  35. music.setYear(Integer.parseInt(str));

  36. }

  37. }

  38. }

  39. @Override

  40. publicvoidendElement(Stringuri,StringlocalName,StringqName)

  41. throwsSAXException{

  42. if("music".equals(localName)&&null!=music){

  43. musics.add(music);

  44. music=null;

  45. }

  46. preTag=null;

  47. }

  48. @Override

  49. publicvoidendDocument()throwsSAXException{

  50. }

  51. publicListgetMusics(){

  52. returnmusics;

  53. }

  54. }

对外提供SAX解析服务的接口SaxService:

 
     
  1. publicclassSaxService{

  2. publicstaticListreadXml(InputStreamis)throwsException{

  3. SAXParserFactorysaxFactory=SAXParserFactory.newInstance();

  4. SAXParserparser=saxFactory.newSAXParser();

  5. //parser.setProperty("http://xml.org/sax/features/namespaces",true);

  6. SaxHandlerhandler=newSaxHandler();

  7. parser.parse(is,handler);

  8. returnhandler.getMusics();

  9. }

  10. }

测试方法:

 
     
  1. publicvoidtestSaxRead(){

  2. InputStreamis=XmlPaserTest.class.getClassLoader().getResourceAsStream("musics.xml");

  3. try{

  4. Listmusics=SaxService.readXml(is);

  5. for(MusicEntitymusic:musics){

  6. Log.i("lanyan",music.toString());

  7. }

  8. }catch(Exceptione){

  9. e.printStackTrace();

  10. }

  11. }

Pull:

同样是事件驱动,不同的是不需要实现什么handler接口,标签之间value的读取也不需要通过类似characters(...)的回调方法,相关API已经封转好了

对外提供PULL解析服务的接口PullService中的xml解析方法:

 
     
  1. publicstaticListreadXml(InputStreamis)throwsException{

  2. Listmusics=null;

  3. XmlPullParserparser=Xml.newPullParser();

  4. parser.setInput(is,"UTF-8");

  5. inteventCode=parser.getEventType();//事件类型

  6. MusicEntitymusic=null;

  7. while(eventCode!=XmlPullParser.END_DOCUMENT){

  8. switch(eventCode){

  9. caseXmlPullParser.START_DOCUMENT://开始文档事件

  10. musics=newArrayList();

  11. break;

  12. caseXmlPullParser.START_TAG://元素开始标志

  13. if("music".equals(parser.getName())){

  14. music=newMusicEntity();

  15. music.setId(newInteger(parser.getAttributeValue(0)));

  16. }elseif(music!=null){

  17. if("name".equals(parser.getName())){

  18. music.setName(parser.nextText());//拿到标签后第一个文本节点的value

  19. }elseif("albumName".equals(parser.getName())){

  20. music.setAlbumName(parser.nextText());

  21. }elseif("year".equals(parser.getName())){

  22. music.setYear(Integer.parseInt(parser.nextText()));

  23. }

  24. }

  25. break;

  26. caseXmlPullParser.END_TAG://元素结束标志

  27. if("music".equals(parser.getName())&&music!=null){

  28. musics.add(music);

  29. music=null;

  30. }

  31. break;

  32. }

  33. eventCode=parser.next();

  34. }

  35. returnmusics;

  36. }

使用PULL解析方式生成xml文件:

PullService中的xml生成方法:

 
     
  1. /**

  2. *Pull生成xml数据

  3. *@parampersons

  4. *@paramwriter

  5. *@throwsException

  6. */

  7. publicstaticvoidwriteXml(List<MusicEntity>musics,Writerwriter)

  8. throwsException{

  9. XmlSerializerserializer=Xml.newSerializer();

  10. serializer.setOutput(writer);

  11. serializer.startDocument("UTF-8",true);

  12. serializer.startTag(null,"musics");

  13. for(MusicEntitymusic:musics){

  14. serializer.startTag(null,"music");

  15. serializer.attribute(null,"id",String.valueOf(music.getId()));

  16. serializer.startTag(null,"name");

  17. serializer.text(music.getName());

  18. serializer.endTag(null,"name");

  19. serializer.startTag(null,"albumName");

  20. serializer.text(music.getAlbumName());

  21. serializer.endTag(null,"albumName");

  22. serializer.startTag(null,"year");

  23. serializer.text(String.valueOf(music.getYear()));

  24. serializer.endTag(null,"year");

  25. serializer.endTag(null,"music");

  26. }

  27. serializer.endTag(null,"musics");

  28. serializer.endDocument();

  29. writer.flush();

  30. writer.close();

  31. }

测试方法:

 
     
  1. publicvoidtestPullWrite()throwsException{

  2. Listmusics=newArrayList();

  3. MusicEntitymusic1=newMusicEntity();

  4. music1.setId(1);

  5. music1.setName("七里香");

  6. music1.setAlbumName("七里香");

  7. music1.setYear(2004);

  8. musics.add(music1);

  9. MusicEntitymusic2=newMusicEntity();

  10. music2.setId(1);

  11. music2.setName("一路向北");

  12. music2.setAlbumName("十一月的萧邦");

  13. music2.setYear(2005);

  14. musics.add(music2);

  15. //写入文件

  16. //Filefile=newFile(Environment.getExternalStorageDirectory(),"musics.xml");

  17. //BufferedWriterwriter=newBufferedWriter(newOutputStreamWriter(newFileOutputStream(file)));

  18. //以字符串形式输出

  19. StringWriterwriter=newStringWriter();

  20. PullService.writeXml(musics,writer);

  21. Log.i("lanyan",writer.toString());

  22. }

输出结果:

 
     
  1. xmlversion='1.0'encoding='UTF-8'standalone='yes'?><musics><musicid="1"><name>七里香name><albumName>七里香albumName><year>2004year>music><musicid="1"><name>一路向北name><albumName>十一月的萧邦albumName><year>2005year>music>musics>