JAVA-使用SAX解析XML資料

cxmscb發表於2016-07-22

一、SAX (Simple API for XML)

  1. SAX解析XML檔案採用的是事件驅動,它不需要解析完整個文件,而是一邊按內容順序解析文件,一般判斷當前讀到的字元是否符合XML語法中的某部分,如果符合則會回撥一些函式來處理事件。
  2. 使用SAX的優點:SAX採用流的形式來處理,佔用記憶體少。

二、事件處理器DefaultHandler

  1. 事件驅動的回撥函式在DefaultHandler中,因此需要寫一個DefaultHandler子類,然後在回撥函式中處理相關的事件。

    public class XMLPersonHandler extends DefaultHandler {
    
    
        @Override
        public void startDocument() throws SAXException {
    
            //開始解析xml之前的預處理
        }
    
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    
             // 解析到節點的開頭標籤'<...'時被呼叫
    
             // uri:名稱空間
             // localName:不帶名稱空間字首的標籤名
             // qName:帶名稱空間的標籤名
    
             // attributes:標籤的屬性集合 <person id="001"></person>
             // 如上,屬性id在attributes中,獲取標籤資料如下:
            // attributes.getQName( ),attributes.getValue( )
    
    
        }
    
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
    
            // 讀取**開頭標籤**到'>'時被呼叫,獲取標籤所夾的內容。
            //<name>Jack</name>
    
            // ch[]:內容
            // start:起始位置
            // length:長度
    
            //獲取內容:new String(ch,start,length);
    
        }
    
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
    
             //解析到結束標籤時被呼叫 '/>'
             //<name>Jack</name>
    
    
        }
    
        @Override
        public void endDocument() throws SAXException {
            //文件解析結束時被呼叫
        }
    }
    

三、解析器SAXParser

  1. 獲取解析器:

    SAXParserFactory spf = SAXParserFactory.newInstance();
    SAXParser sp =  spf.newSAXParser();
    
  2. 解析XML資料:

    //inputStream為讀取XML資料時的輸入流
    
    XMLPersonHandler mhandler = new XMLPersonHandler();
    sp.parse(inputStream, mhandler);
    

四、對DefaultHandler子類的封裝

  1. XML中的資料獲取主要在自定義DefaultHandler子類中,所以可以在子類裡面進行資料的獲取和封裝。

  2. 對xml的結點資料內容獲取的簡單封裝:(不適合層次深的結點資料獲取)

    public class XMLGeneralHandler extends DefaultHandler {
    
    
        private HashMap<String,String> map = null;
        private List<HashMap<String,String>> list = null;
        private String currentTag = null;
        private String currentValue = null;
    
        private String nodeName = null;
    
        public XMLGeneralHandler(String nodeName){
            this.nodeName = nodeName;
        }
    
    
        public List<HashMap<String,String>> getList(){
            return list;
        }
    
    
        @Override
        public void startDocument() throws SAXException {
            list = new ArrayList<>();
        }
    
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                if(qName.equals(nodeName)){
                  map = new HashMap<String,String>();
    
                if(attributes!=null && map!=null){
                    for(int i=0;i<attributes.getLength();i++){
                        map.put(attributes.getQName(i), attributes.getValue(i));
                        }
                    }
                }
                currentTag = qName;
    
        }
    
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
    
            if(currentTag!=null && map!=null){
    
                currentValue = new String(ch,start,length);
                if(currentValue!=null&&!currentValue.trim().equals("")&&!currentValue.trim().equals("\n")){
                    map.put(currentTag,currentValue);
                }
    
            }
    
            currentTag = null;
            currentValue = null;
    
        }
    
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
               if(qName.equals(nodeName)){
                   list.add(map);
                   map = null;
               }
        }
    
        @Override
        public void endDocument() throws SAXException {
    
        }
    }
    
  3. 對一些層次比較深的結點資料,可以自定義的通過結點資料的資訊來特定封裝。

五、程式碼測試:

獲取IT之家的新聞xml資料。

  1. 獲取xml資料的輸入流:

    public class HttpUtil {
    
        public static InputStream getXML(String path){
    
            InputStream inputStream = null;
            try{
    
                URL url = new URL(path);
                if(url!=null){
    
                      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                      connection.setConnectTimeout(5000);
                      connection.setDoInput(true);
                      connection.setRequestMethod("GET");
                      int code = connection.getResponseCode();
                      if(code == 200){
                          inputStream = connection.getInputStream();
                      }
    
                }
    
    
            }catch(Exception e){
    
            }
    
    
    
            return inputStream;
        }
    
    }
    
  2. 封裝的DefaultHandler子類:XMLGeneralHandler (如上)

  3. 測試類:

    public class Test {
    
        public static void main(String[] args) {
    
    
            String path = "http://api.ithome.com/xml/newslist/news.xml";
            System.out.println(path);
            InputStream inputStream = HttpUtil.getXML(path);
            try{
    
                List<HashMap<String,String>> list = null;
    
                SAXParserFactory spf = SAXParserFactory.newInstance();
                SAXParser sp =  spf.newSAXParser();
                XMLGeneralHandler mhandler = new XMLGeneralHandler("item");
                sp.parse(inputStream, mhandler);
                inputStream.close();
    
                list = mhandler.getList();
    
                for(HashMap<String,String> p:list){
                    System.out.println(p.toString());
                }
    
            }catch(Exception e){
    
            }
    
    
        }
    
    }
    
  4. 列印輸出:

六、與PULL、DOM解析比較

  1. Dom解析xml,是先把全部資料讀入到記憶體中,然後檢索想要的資料,比較消耗記憶體,在xml文件比較小的情況下也可以考慮使用dom方式。
  2. android系統中,很多資原始檔都是xml格式,android系統解析這些xml的方式,是使用pul解析器進行解析的,也是採用事件驅動進行解析的。解析應用本地的xml可以採用pull解析。

相關文章