zoukankan      html  css  js  c++  java
  • Android DOM解析XML方法及优化

         在Android应用开发中,我们常常要在应用启动后从服务器下载一些配置文件,这些配置文件包含一些项目中可能用到的资源,这些文件很多情况下是XML文件,这时就要将XML下载到文件中保存,之后再解析XML。解析XML的方法有DOM, SAX, JDOM, DOM4J,本文中只使用了DOM,下面先介绍DOM的基础知识和解析XML的方法,然后再结合一个项目实例来实现从XML文件的下载到解析整个过程。

          DOM(Document Object Model,文档对象模型)定义了访问和操作XML的标准方法。基于DOM的XML解析器会将整个XML文档转化成对象模型集合,这个集合是树结构。这样我们就可以通过DOM接口来访问任意的节点,整个DOM树的结构和XML文档的数据分层结构相似,所以对开发者来说DOM接口的使用就很方便和直观了。但是,不足之处在于,由于这个DOM树是保存在内存中的,如果XML文档中数据很多,结构很复杂,那么就会导致其对内存的要求高,遍历一次的时间长。

          下面来看一个XML文档中数据的例子。

    <bookstore>
    
    <book category="children">
       <title lang="en">Harry Potter</title> 
       <author>J K. Rowling</author> 
       <year>2005</year> 
       <price>29.99</price> 
    </book>
    
    </bookstore>

    该文档转化成DOM树,如下

    在DOM数中,XML文档中每个成分都是一个节点。

            1.整个XML文档是一个文档节点;

            2.每个XML标签是一个元素节点;

            3.包含在XML标签中的文本是一个文档节点;

            4.每个XML属性是一个属性节点;

            5.注释属于注释节点。

               需要注意的是:<year>2005</year> 中的year是一个元素节点,2005是元素节点year的子节点(文本节点)的值,不是year节点的值。

    DOM中节点的属性

             nodeName节点的名称

                    元素节点nodeName与标签名相同

                    属性节点nodeName与属性的名称

                    文本节点nodeName永远是#text

                    文档节点nodeName永远是#document

             nodeValue节点的值

                    元素节点的nodeValue值是undefined

                    文本节点的nodeValue值是文本本身

                    属性节点的nodeValue是属性值

              nodeType节点的类型

                    元素节点:1

                    属性节点:2

                    文本节点:3

                    注释节点:4

                    文档节点:9

    DOM中的方法

             getElementsByTagName()返回拥有指定名标签的所有元素。          

    xmlDoc=loadXMLDoc("books.xml");  
    x=xmlDoc.getElementsByTagName("title");  

        使用childNodes 或 getElementsByTagName() 属性或方法时,会返回 NodeList 。在NodeList中保存的节点不包含属性节点。

           元素节点的 attributes 属性返回属性节点的列表。

    xmlDoc=loadXMLDoc("books.xml");  
    x=xmlDoc.getElementsByTagName("book")[0].attributes;  

    下面结合在项目开发中的一个实例来完整的介绍DOM解析XML方法的使用。

        1. 从服务器端下载XML文档并保存到本地

    /**
     *  从服务器端下载配置文件,并保存在basesettings.xml中
     *   
     */
     private void downLoadConfigXml(){
         
         String sValue=null;
         sValue=PLATE_WWW+“baseconfig.xml”  //得到URL,PLATE_WWW是平台的URL
         Log.i(TAG,"baseconfig sValue=="+sValue);
         final String url=sValue;
          
         //开启一个新的线程来下载XML文档
         new Thread(){
           public void run(){
              HttpClient client=new DefaultHttpClient();
              HttpGet get=new HttpGet(url);
              HttpResponse response;
              try{
                 response=client.execute(get);
                 HttpEntity entity=response.getEntity();
                 long length=entity.getContentLength();
                 InputSteam is=entity.getContent();
                 FileOutputStream fileOutputStream=null;
                 if(is!=null){
                    //开启存放XML文档的文件流
                    fileOutputStream=openFileOutput("baseconfig.xml",
                           Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITLEABLE);
                    byte[]buf=new byte[1024];
                    int ch=-1;
                    while((ch=is.read(buf))!=-1){
                       Log.i(TAG,"ConfigXml下载中...");
                       fileOutputStream.write(buf,0,ch);
                    }
                 }
                 fileOutputStream.flush();
                 //下载完毕,关闭文件流
                 if(fileOutputStream!=null){
                    fileOutputStream.close();
                 }
                 Log.i(TAG,"ConfigXml下载完成");
              }catch(ClientProtocolException e){
                   e.printStackTrace();
                   //下载出现错误,通过Handler来做出UI上的提示
                   mHandler .obtainMessage(GlobalDef.WM_ALL_SERVER_FAIL).sendToTarget();
              }catch(){
                   e.printStackTrace();
                   //下载出现错误,通过Handler来做出UI上的提示
                   mHandler .obtainMessage(GlobalDef.WM_ALL_SERVER_FAIL).sendToTarget();
              }
           }
         }.start();     
     }

         2.创建DOM解析器

    /** 
    *  DOM解析器:包含对XML文档的加载和解析方法 
    */  
    public class MyXml{  
        Document mDocument;//代表整个XML文档树,其nodeName为#document  
        Element mDocRoot;//根节点,也是一个元素节点  
        NodeList mNodeList;//节点链表  
        Node mNode;//节点  
        int mNodeIndex=0;//遍历树时的索引  
          
        //DOM加载XML文档:有以下三种  
        public boolean loadXML(byte[] sXML){  
          
           DocumentBuilderFactory docFactory=DocumentBuildFactory.newInstance();  
           DocumentBuild docBuilder;  
           try{  
               docBuilder=docFactory.newDocumentBuilder();  
               InputStream is=new ByteArrayInputStream(sXML);  
               mDocument=docBuilder.parse(is,"GB2312");//文档节点  
               mDocRoot=mDocument.getDoucmentElement();//返回DOM树的根结点      
           }catch(Exception e){  
             e.printStackTrace();  
             return false;  
           }  
           return true;  
        }  
          
          
        public boolean loadXML(byte[] sXML, String sCodec)//设置编码形式  
        {  
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder docBuilder;  
            try {  
                String str = new String(sXML, sCodec);  
                docBuilder = docFactory.newDocumentBuilder();  
                InputStream is = new ByteArrayInputStream(str.getBytes());  
                  
                mDocument = docBuilder.parse(is);  
                mDocRoot = m_Document.getDocumentElement();  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
                return false;             
            }   
            return true;  
        }  
          
        public boolean loadIS(InputStream is, String sCodec)  
        {  
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder docBuilder;  
            try {  
                docBuilder = docFactory.newDocumentBuilder();  
                mDocument = docBuilder.parse(is);  
                mDocRoot = m_Document.getDocumentElement();//获取根节点  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
                return false;             
            } catch (OutOfMemoryError e) {  
                e.printStackTrace();  
                return false;             
            }  
            return true;  
        }  
    }  

    所要解析的XML文档内容

    <items>  
    <gifthead>  
    <gifttype>1</gifttype>  
    <giftname>初次相见</giftname>  
    <giftsort>1</giftsort>  
    </gifthead>  
    <item>  
    <index>100001</index>  
    <picname>100001.bmp</picname>  
    <bigpicname>100001.gif</bigpicname>  
    <itemname>鲜花</itemname>  
    </item>  
    <NewVer>1</NewVer>  
    </items>  

    我们通过DOM在XML中寻找节点时,往往效率低下,因为每寻找一个节点就需要从新遍历一次DOM树,在这里我在MyXml类中封装了方法GetNodeList,可以把要查询的节点的路径作为参数传入,这样就可以优化这个查询效率。比如<item>的子节点中的<picname>节点,那么以picname/item/items的形式传入,即可获得所有的item节点下的picname节点。

    public boolean SelectNodeToList(String sExpress)  
        {  
            if(mDocRoot==null)  
                return false;  
            mNodeList = GetNodeList(sExpress);  
            mNodeIndex = 0;  
            if(mNodeList !=null)  
            {  
                return true;  
            }  
            else  
                return false;  
        }  
          
        public NodeList GetNodeList(String sExpress)  
        {  
            if(mDocRoot==null)  
                return null;  
            try {  
                String [] sNodePaths = sExpress.split("/");//用“/”来分隔String,分隔后的字段中没有“/”,得到[, , items]  
                  
                Element currentNode = m_DocRoot;  
                List<String> sNodeTree = new ArrayList<String>();  
                for(int i = 0;i<sNodePaths.length;i++)  
                {  
                    if(sNodePaths[i].length()!=0)  
                    {  
                        sNodeTree.add(sNodePaths[i]);//“item”加到List中  
                    }  
                }  
                for(int i = 0;i<sNodeTree.size() - 1;i++)  
                {  
    //              Log.i(i+": ");  
    //              Log.i(sNodeTree.get(i));  
                    if(!sNodeTree.get(i).equals(""))  
                    {  
    //                  Log.i("currentNode = (Element) (currentNode.getElementsByTagName(sNodeTree.get(i))).item(0);");  
                        currentNode = (Element) (currentNode.getElementsByTagName(sNodeTree.get(i))).item(0);//获取根节点的子节点中所有名为items节点集合中的第一个节点  
                    }  
                }  
    //          Log.i(sNodeTree.size()-1+": ");  
    //          Log.i(sNodeTree.get(sNodeTree.size()-1));  
                mNodeList = currentNode.getElementsByTagName(sNodeTree.get(sNodeTree.size()-1));  
                if(mNodeList.getLength() == 0 && currentNode.getNodeName().equals(sNodeTree.get(sNodeTree.size()-1)) &¤tNode == mDocRoot)  
                {  
                    mNodeList = mDocument.getChildNodes();  
                }//修正Android4.0系统收不到消息的bug  
                  
            } catch (Exception e) {  
                Log.i(TAG, "GetNodeList m_NodeList = currentNode.getElementsByTagName(sNodeTree.get(sNodeTree.size()-1)) error.");  
                e.printStackTrace();  
                return null;  
            }  
            if(mNodeList !=null)  
            {  
                return mNodeList;  
            }  
            else  
                return null;  
        }  
          
        public Node GetNode(String sExpress)  
        {  
            if(mDocRoot==null)  
                return null;  
            if(sExpress.equals("."))  
                return m_DocRoot;  
          
            try {  
      
                String [] sNodePaths = sExpress.split("/");  
                  
                Element currentNode = m_DocRoot;  
                List<String> sNodeTree = new ArrayList<String>();  
                for(int i = 0;i<sNodePaths.length;i++)  
                {  
                    if(sNodePaths[i].length()!=0)  
                    {  
                        sNodeTree.add(sNodePaths[i]);  
                    }  
                }  
                for(int i = 0;i<sNodeTree.size() - 1;i++)  
                {  
    //              Log.i(i+": ");  
    //              Log.i(sNodeTree.get(i));  
                    if(!sNodeTree.get(i).equals(""))  
                    {  
    //                  Log.i("currentNode = (Element) (currentNode.getElementsByTagName(sNodeTree.get(i))).item(0);");  
                        currentNode = (Element) (currentNode.getElementsByTagName(sNodeTree.get(i))).item(0);  
                    }  
                }  
    //          Log.i(sNodeTree.size()-1+": ");  
    //          Log.i(sNodeTree.get(sNodeTree.size()-1));  
                  
                mNodeList = currentNode.getElementsByTagName(sNodeTree.get(sNodeTree.size()-1));  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            if(mNodeList !=null)  
            {  
                return mNodeList.item(0);  
            }  
            else  
                return null;  
        }  
          
        public Node QueryNode(boolean bReset)  
        {  
    //      Log.i("QueryNode "+bReset);  
            if (bReset)  
            {  
                mNodeIndex = 0;  
                return mNodeList.item(mNodeIndex);  
            }  
              
            try  
            {  
    //          Log.i("QueryNode "+bReset);  
                mNode = null;  
                mNode = mNodeList.item(mNodeIndex);  
                mNodeIndex++;  
    //          Log.i("mNodeIndex"+mNodeIndex+"="+mNode);     
            }  
            catch(Exception e)  
            {  
                Log.w(TAG, "QueryNode mNode = mNodeList.item(mNodeIndex) error.");  
            }  
              
            return m_Node;  
        }  
      
        //获取m_Node节点下指定的节点的值  
        public String GetValueByName(String sName)  
        {  
            //Log.i(TAG, "GetValueByName: sName = "+sName);  
            Element element = (Element)m_Node;  
            String sValue = null;  
            if(sName.equals("."))  
            {  
                try{  
                    sValue = mNode.getFirstChild().getNodeValue();  
                }catch(Exception e){  
                    Log.i(TAG, "GetValueByName("+ sName +") --> sValue = mNode.getFirstChild().getNodeValue() error.");  
                }     
            }  
            else  
            {  
                try  
                {  
                    NodeList nodelist = element.getElementsByTagName(sName);  
                    if(nodelist != null)  
                    {  
                        sValue = nodelist.item(0).getFirstChild().getNodeValue();  
                    }  
                }catch(Exception e){  
    //              Log.i(TAG, "GetValueByName ("+ sName +") --> sValue = nodelist.item(0).getFirstChild().getNodeValue() error.");  
                }  
            }  
            if(sValue==null)  
            {  
    //          Log.w(TAG, sName+"节点值sValue==null, Return");  
            }  
            return sValue;  
        }  
  • 相关阅读:
    用redis实现分布式锁
    mac下Nginx+lua模块编译安装
    ESXi5 中克隆Linux虚拟主机的网络配置
    DOS命令中的For
    让delphi解析chrome扩展的native应用
    C语言 cgi(3)
    C语言 cgi(2)
    C语言cgi(1)
    c++ input,output
    Array of Objects
  • 原文地址:https://www.cnblogs.com/chengzhengfu/p/4581715.html
Copyright © 2011-2022 走看看