XML的解析与生成
Android平台上可以使用 Simple API for XML (SAX),Document Object Model(DOM) 和Android 附带的pull解析器 解析XML文件
众所周知,,DOM解析方式很耗内存,优先使用SAX或者pull
SAX:
解析速度快,占用内存少,采用事件驱动,即不需要加载完整个文档,而是按内容顺序解析文档,在此过程中,其会判断当前读到的内容是否符合XML语法定义,如果符合就会触发事件,所谓事件,其实就是一些callback方法,具体方法含义比较简单,看文档即可,定义在DefaultHandler接口中(SAX已内置到JDK5.0中)
待解析xml文件musics.xml:
<?xml version="1.0" encoding="utf-8"?><musics><music id="1"><name>黑色幽默</name><albumName>Jay</albumName><year>2000</year></music><music id="2"><name>爱在西元前</name><albumName>范特西</albumName><year>2001</year></music><music id="3"><name>回到过去</name><albumName>八度空间</albumName><year>2002</year></music><music id="4"><name>东风破</name><albumName>叶惠美</albumName><year>2003</year></music><music id="5"><name>七里香</name><albumName>七里香</albumName><year>2004</year></music><music id="6"><name>一路向北</name><albumName>十一月的萧邦</albumName><year>2005</year></music></musics>
实体类MusicEntity就不贴了,四个属性,上面的xml中也可以看出.
实现了DefaultHandler接口的SaxHandler:
publicclass SaxHandler extends DefaultHandler{ privatestaticfinal String TAG = "lanyan"; private List<MusicEntity> musics; private MusicEntity music; //缓存上一次的标签名private String preTag; @Override publicvoid startDocument() throws SAXException { musics = new ArrayList<MusicEntity>(); } @Override publicvoid startElement(String uri,String localName,String qName,Attributes attributes) throws SAXException { if ("music".equals(localName)) { music = new MusicEntity(); music.setId(Integer.parseInt(attributes.getValue("id"))); } preTag = localName; } /** * 解析到文档中字符内容时调用 * 所以一般网络中传输的xml,其父节点与子节点之间是紧挨在一起的,基本上就是一行,看起来很混乱,其实是为了避免解析时无必要的调用 * 这里仅是测试,故忽略这个因素 */ @Override publicvoid characters(char[] ch,int start,int length) throws SAXException { if (null != music) { String str = new String(ch,start,length); if ("name".equals(preTag)) { music.setName(str); } elseif ("albumName".equals(preTag)) { music.setAlbumName(str); } elseif ("year".equals(preTag)) { music.setYear(Integer.parseInt(str)); } } } @Override publicvoid endElement(String uri,String qName) throws SAXException { if ("music".equals(localName) && null != music) { musics.add(music); music = null; } preTag = null; } @Override publicvoid endDocument() throws SAXException { } public List<MusicEntity> getMusics() { return musics; } }
对外提供SAX解析服务的接口SaxService:
publicclass SaxService { publicstatic List<MusicEntity> readXml(InputStream is) throws Exception { SAXParserFactory saxFactory = SAXParserFactory.newInstance(); SAXParser parser = saxFactory.newSAXParser();// parser.setProperty("http://xml.org/sax/features/namespaces",true); SaxHandler handler = new SaxHandler(); parser.parse(is,handler); return handler.getMusics(); } }
测试方法:
publicvoid testSaxRead() { InputStream is = XmlPaserTest.class.getClassLoader().getResourceAsStream("musics.xml"); try { List<MusicEntity> musics = SaxService.readXml(is); for (MusicEntity music : musics) { Log.i("lanyan",music.toString()); } } catch (Exception e) { e.printStackTrace(); } }
Pull:
同样是事件驱动,不同的是不需要实现什么handler接口,标签之间value的读取也不需要通过类似characters(...)的回调方法,相关API已经封转好了
对外提供PULL解析服务的接口PullService中的xml解析方法:
publicstatic List<MusicEntity> readXml(InputStream is) throws Exception { List<MusicEntity> musics = null; XmlPullParser parser = Xml.newPullParser(); parser.setInput(is,"UTF-8"); int eventCode = parser.getEventType();// 事件类型 MusicEntity music = null; while (eventCode != XmlPullParser.END_DOCUMENT) { switch (eventCode) { case XmlPullParser.START_DOCUMENT:// 开始文档事件 musics = new ArrayList<MusicEntity>(); break; case XmlPullParser.START_TAG:// 元素开始标志if ("music".equals(parser.getName())) { music = new MusicEntity(); music.setId(new Integer(parser.getAttributeValue(0))); } elseif (music != null) { if ("name".equals(parser.getName())) { music.setName(parser.nextText());// 拿到标签后第一个文本节点的value } elseif ("albumName".equals(parser.getName())) { music.setAlbumName(parser.nextText()); } elseif ("year".equals(parser.getName())) { music.setYear(Integer.parseInt(parser.nextText())); } } break; case XmlPullParser.END_TAG://元素结束标志if ("music".equals(parser.getName()) && music != null) { musics.add(music); music = null; } break; } eventCode = parser.next(); } return musics; }
/** * Pull生成xml数据 * @param persons * @param writer * @throws Exception */publicstaticvoid writeXml(List<MusicEntity> musics,Writer writer) throws Exception { XmlSerializer serializer = Xml.newSerializer(); serializer.setOutput(writer); serializer.startDocument("UTF-8",true); serializer.startTag(null,"musics"); for (MusicEntity music : musics) { serializer.startTag(null,"music"); serializer.attribute(null,"id",String.valueOf(music.getId())); serializer.startTag(null,"name"); serializer.text(music.getName()); serializer.endTag(null,"name"); serializer.startTag(null,"albumName"); serializer.text(music.getAlbumName()); serializer.endTag(null,"albumName"); serializer.startTag(null,"year"); serializer.text(String.valueOf(music.getYear())); serializer.endTag(null,"year"); serializer.endTag(null,"music"); } serializer.endTag(null,"musics"); serializer.endDocument(); writer.flush(); writer.close(); }
测试方法:
publicvoid testPullWrite() throws Exception { List<MusicEntity> musics = new ArrayList<MusicEntity>(); MusicEntity music1 = new MusicEntity(); music1.setId(1); music1.setName("七里香"); music1.setAlbumName("七里香"); music1.setYear(2004); musics.add(music1); MusicEntity music2 = new MusicEntity(); music2.setId(1); music2.setName("一路向北"); music2.setAlbumName("十一月的萧邦"); music2.setYear(2005); musics.add(music2); //写入文件// File file = new File(Environment.getExternalStorageDirectory(),"musics.xml");// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))); //以字符串形式输出 StringWriter writer = new StringWriter(); PullService.writeXml(musics,writer); Log.i("lanyan",writer.toString()); }
输出结果:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><musics><music id="1"><name>七里香</name><albumName>七里香</albumName><year>2004</year></music><music id="1"><name>一路向北</name><albumName>十一月的萧邦</albumName><year>2005</year></music></musics>