解析XML格式数据的三种方法Pull,Sax,Dom

本文介绍了XML解析的三种方法——DOM、SAX和Pull解析的优缺点。DOM解析易于使用,但内存占用高,不适合大文件;SAX解析效率高,资源占用少,但数据不持久;Pull解析结合了两者优点,但修改文档不便。通过代码示例展示了每种解析方式的使用方法,供开发者选择合适的解析策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

既然要介绍这三种解析方法那么当然要说一下为什么用他们,用他们有什么优点和缺点。

首先说一下Dom解析:

优点:易用性强,使用DOM时,将把所有的XML文档信息都存于内存中,并且遍历简单,支持XPath,增强了易用性。

缺点:效率低,解析速度慢,内存占用量过高,对于大文件来说几乎不可能使用。另外效率低还表现在大量的消耗时间,因为使用DOM进行解析时,将为文档的每个element、attribute、processing-instrUCtion和comment都创建一个对象,这样在DOM机制中所运用的大量对象的创建和销毁无疑会影响其效率。

接着说Sax解析:

优点:不用事先调入整个文档,占用资源少。尤其在嵌入式环境,如Android,极力推荐采用SAX进行解析。

缺点:不像DOM一样将文档树长期留驻在内存,数据不是长久的。事件过后,若没保存数据,那么数据就会丢失。

然后Pull解析:

优点:不必自己写事件逻辑,并且也不需要把文档读到内存。个人感觉优于以上两种解析方式。

缺点:对文档修改比较困难。

下面用代码来演示一下用法:

首先添加一下XML格式内容:


<apps>
	<app>
		<id>1</id>
		<name>Google Map</name>
		<version>1.0</version>
		</app>
		<app>
		<id>2</id>
		<name>Chrome</name>
		<version>2.1</version>
		</app>
		<app>
		<id>3</id>
		<name>Google</name>
		<version>2.3</version>
	</app>
</apps>

Pull解析:

运行结果如下:

主要代码如下:

 private void parseXMLWithPull(String responseData) {
        try{
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(responseData));
            int evenType = xmlPullParser.getEventType();
            String id = "";
            String name = "";
            String version = "";
            while(evenType!=XmlPullParser.END_DOCUMENT){
                String nodeName = xmlPullParser.getName();
                switch (evenType){
                    //开始解析某个节点
                    case XmlPullParser.START_TAG:{
                        if ("id".equals(nodeName)){
                            id = xmlPullParser.nextText();
                        }else if ("name".equals(nodeName)){
                            name = xmlPullParser.nextText();
                        }else if ("version".equals(nodeName)){
                            version = xmlPullParser.nextText();
                        }break;
                    }
                    //解析完成某个节点
                    case XmlPullParser.END_TAG:{
                        if ("app".equals(nodeName)){
                            Log.d("MainActivity","id is"+ id);
                            Log.d("MainActivity","name is"+ name);
                            Log.d("MainActivity","Version is"+ version);
                        }
                        break;
                    }
                    default:
                        break;
                }
                evenType = xmlPullParser.next();
            }
        }catch (Exception e){
            e.printStackTrace();
        }

SAX解析:

首先要创建一个类继承ContentHandler,并重写父类的五个方法。

public class ContentHandler extends DefaultHandler {
    private String nodeName;
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;
        //在开始XML解析的时候调用
    @Override
    public void startDocument() throws SAXException {
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }
        //在开始解析某个节点时候调用
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //记录当前节点名
        nodeName = localName;
    }
        //在获取节点内容的时候调用
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //根据当前节点名判断将内容添加到哪一个StringBuilder对象中
        if ("id".equals(nodeName)){
            id.append(ch,start,length);
        }else if ("name".equals(nodeName)){
            name.append(ch, start, length);
        }else if ("version".equals(nodeName)){
            version.append(ch, start, length);
        }
    }
        //在完成解析某个节点的时候调用
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ("app".equals(localName)){
            Log.d("ContentHandler","id is"+id.toString().trim());
            Log.d("ContentHandler","name is"+name.toString().trim());
            Log.d("ContentHandler","version is"+version.toString().trim());
            //最后要将StringBuilder清除掉
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }
        //在完成整个XML解析的时候调用
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}

然后再得到了服务器数据后就要到MainActivity中创建一个方法把数据解析出来

  @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}
private void parseXMLWithSAX(String xmlData){
    try{
        SAXParserFactory factory = SAXParserFactory.newInstance();
        XMLReader xmlReader = factory.newSAXParser().getXMLReader();
        ContentHandler handler = new ContentHandler();
        //将ContentHandler实例设置到XMLReader中
        xmlReader.setContentHandler(handler);
        //开始执行解析
        xmlReader.parse(new InputSource(new StringReader(xmlData)));
    }catch (Exception e){
        e.printStackTrace();
    }
}

 

DOM解析:

    /**
     * dom解析,该方法里的代码演示了如何利用DOM解析,拿到该xml文档的所有信息,如根节点名称,属性,和该根节点包含的
     * 所有子节点的所有信息(子节点的属性,文本内容,子节点又包含的子节点等等)
     */
    public void DomParse(View view) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            //从assets目录获取xml文档输入流
            AssetManager assets = getAssets();
            InputStream is = assets.open("text.xml");
            //通过 builder.parse(is)方法获取一个document实例
            Document document = builder.parse(is);
            //根节点相关
            Element element = document.getDocumentElement();//获取当前xml文档的所有信息
            element.getTagName();//返回根节点的名称,这里为:note
            element.getAttribute("name");//根据根节点的属性名返回属性值,这里为:rqq
            //子节点相关
            NodeList nodeList = element.getElementsByTagName("*");//根据子节点的节点名返回一个节点列表,如果填写"*",则返回所有节点的列表信息
            nodeList.item(0).getNodeName();//返回第0个位置子节点的节点名,这里为:to
            nodeList.item(0).getTextContent();//返回第0个位置子节点里的文本内容,不是属性值,这里为:George
            nodeList.item(0).getParentNode();//返回第0个位置子节点的父节点,因各种原因找不到父节点则返回null,这里为:note
            nodeList.item(0).getChildNodes();//返回第0个位置子节点包含的所有子节点列表信息,没有子节点,也会返回一个NodeList,只不过长度为0,这里当前的子节点<span style="white-space:pre">					</span>     //下面已经没有子节点了,所以返回的NodeList长度为0
            NamedNodeMap map = nodeList.item(0).getAttributes();//获取第0个位置子节点所有的属性集合,这里只有1个属性,即id
            String nodeValue = map.item(0).getNodeValue();//获取第0个位置子节点的第0个位置属性的属性值,这里为:1
            /*
            * //也可通过下面的方式获取
            * //因为Element是Node的子类,所以可以把Node强转为Element
            * Element element1 = (Element) nodeList.item(0);
            * //然后通过Element拿到该子节点的各种属性值
            * element1.getAttribute("id");//获取该子节点的id属性
            * //因为Element继承自Node,所以Element可以使用父类即Node类的所有的public方法,如下:
            * element1.getNodeName();
            * element1.getTextContent();
            * element1.getParentNode();
            * element1.getChildNodes();
            *
            * */
 
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
    }

 

好了以上三种解析方式都给大家列出来了使用方法。也算是各有所长吧。在解析的时候可以选择自己适合的解析方式来使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值