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:

public class SaxHandler extends DefaultHandler{
    
    private static final String TAG = "lanyan";
    
    private List<MusicEntity> musics;
    
    private MusicEntity music;
    //缓存上一次的标签名
    private String preTag;
    
    @Override
    public void startDocument() throws SAXException {
        musics = new ArrayList<MusicEntity>();
    }
    
    @Override
    public void 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
    public void 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);
            } else if ("albumName".equals(preTag)) {
                music.setAlbumName(str);
            } else if ("year".equals(preTag)) {
                music.setYear(Integer.parseInt(str));
            }
        }
        
    }
    
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if ("music".equals(localName) && null != music) {
            musics.add(music);
            music = null;
        }
        preTag = null;
    }
    
    @Override
    public void endDocument() throws SAXException {
    }
    
    public List<MusicEntity> getMusics() {
        return musics;
    }
    
}

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

public class SaxService {
    
    public static 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();
    }
    
}

测试方法:

public void 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解析方法:

public static 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)));
                } else if (music != null) {
                    if ("name".equals(parser.getName())) {
                        music.setName(parser.nextText());// 拿到标签后第一个文本节点的value
                    } else if ("albumName".equals(parser.getName())) {
                        music.setAlbumName(parser.nextText());
                    } else if ("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文件:

PullService中的xml生成方法:

/**
     * Pull生成xml数据
     * @param persons
     * @param writer
     * @throws Exception
     */
    public static void 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();
    }

 测试方法:

public void 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>

 

posted @ 2012-08-16 05:08  当年明月  阅读(2413)  评论(0编辑  收藏  举报