日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

XML解析(一),SAX解析XML

發(fā)布時間:2023/12/3 asp.net 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 XML解析(一),SAX解析XML 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉載自??XML解析(一),SAX解析XML

一、概述

?SAX,全稱Simple API for XML,是一種以事件驅動的XMl API,是XML解析的一種新的替代方法,解析XML常用的還有DOM解析,PULL解析(Android特有),SAX與DOM不同的是它邊掃描邊解析,自頂向下依次解析,由于邊掃描邊解析,所以它解析XML具有速度快,占用內(nèi)存少的優(yōu)點,對于Android等CPU資源寶貴的移動平臺來說是一個巨大的優(yōu)勢。

  • SAX的優(yōu)點:

  • 解析速度快
  • 占用內(nèi)存少
  • SAX的缺點:

  • 無法知道當前解析標簽(節(jié)點)的上層標簽,及其嵌套結構,僅僅知道當前解析的標簽的名字和屬性,要知道其他信息需要程序猿自己編碼
  • 只能讀取XML,無法修改XML
  • 無法隨機訪問某個標簽(節(jié)點)
  • SAX解析適用場合?
  • 對于CPU資源寶貴的設備,如Android等移動設備
  • 對于只需從xml讀取信息而無需修改xml

二、SAX解析的步驟

解析步驟很簡單,可分為以下四個步驟

  • 得到xml文件對應的資源,可以是xml的輸入流,文件和uri
  • 得到SAX解析工廠(SAXParserFactory)
  • 由解析工廠生產(chǎn)一個SAX解析器(SAXParser)
  • 傳入輸入流和handler給解析器,調(diào)用parse()解析
  • 知道了SAX解析的優(yōu)缺點和解析步驟,下面我們通過一個簡單的Demo學習一下SAX解析XML

    三、SAX解析實戰(zhàn)

    新建一個Android工程叫SaxParseXmlDemo,將sax.jar下載放到工程的lib下面并添加到構建路徑中,為了方便,我先將工程的目錄結構列一下:

    1、新建一個xml文件叫users.xml

    <?xml version="1.0" encoding="UTF-8"?> <users><user id="1"><name>畢向東</name><password>bxd123</password></user><user id="2"><name>韓順平</name><password>hsp123</password></user><user id="3"><name>馬士兵</name><password>msb123</password></user> </users>

    2、新建一個JavaBean

    package com.example.saxparsexmldemo;public class User {private long id;private String name;private String password;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;} }

    3、新建一個類XmlParseHandler.java,該類需要繼承DefaultHandler或者實現(xiàn)ContentHandler接口,這里我們通過繼承DefaultHandler(實現(xiàn)了ContentHandler接口)的方式,該類是SAX解析的核心所在,我們要重寫以下幾個我們關心的方法。

    • startDocument():文檔解析開始時調(diào)用,該方法只會調(diào)用一次
    • startElement(String uri, String localName, String qName,?
      Attributes attributes):標簽(節(jié)點)解析開始時調(diào)用

    • uri:xml文檔的命名空間
    • localName:標簽的名字
    • qName:帶命名空間的標簽的名字
    • attributes:標簽的屬性集
    • characters(char[] ch, int start, int length):解析標簽的內(nèi)容的時候調(diào)用

    • ch:當前讀取到的TextNode(文本節(jié)點)的字節(jié)數(shù)組
    • start:字節(jié)開始的位置,為0則讀取全部
    • length:當前TextNode的長度
    • endElement(String uri, String localName, String qName):標簽(節(jié)點)解析結束后調(diào)用
    • endDocument():文檔解析結束后調(diào)用,該方法只會調(diào)用一次

    ?重寫startDocument(),我們在這里初始化User集合,該集合用來存放解析出來的user

    Log.e("startDocument", "startDocument()"); users = new ArrayList<User>();

    ?重寫startElement,在startElement中先判斷當前的標簽是否user,如果是user標簽則說明接下來是一個user的信息,所以我們新建一個User對象用來存放這個user的信息,在這里我們得到當前user標簽的id屬性,封裝到user對象中。并記錄當前的標簽

    Log.e("startElement", localName + "-startElement()");if ("user".equals(localName)) { // 是一個用戶for (int i = 0; i < attributes.getLength(); i++) {Log.e("attributes", "attribute_name:" + attributes.getLocalName(i)+ " attribute_value:" + attributes.getValue(i));user = new User();if("id".equals(attributes.getLocalName(i))){user.setId(Long.parseLong(attributes.getValue(i)));}}}currentTag = localName; // 把當前標簽記錄下來

    ?重寫characters,在characters中解析出當前標簽的內(nèi)容,如果當前標簽為name標簽,則解析name標簽的內(nèi)容封裝到當前User對象的name屬性中,如果當前標簽為password標簽,則解析password標簽的內(nèi)容封裝到當前User對象的password屬性中

    String value = new String(ch,start,length); // 將當前TextNode轉換為StringLog.e("characters", value+"");if("name".equals(currentTag)){ // 當前標簽為name標簽,該標簽無子標簽,直接將上面獲取到的標簽的值封裝到當前User對象中// 該節(jié)點為name節(jié)點user.setName(value);}else if("password".equals(currentTag)){ // 當前標簽為password標簽,該標簽無子標簽,直接將上面獲取到的標簽的值封裝到當前User對象中// 該節(jié)點為password節(jié)點user.setPassword(value);}

    ?重寫endElement,在這個方法中判斷當前是否是user標簽的結束,如果是user標簽結束,則這個user信息解析結束,并將當前的User對象和當前的標簽重置

    Log.e("endElement", localName + "-endElement()");if("user".equals(localName)){users.add(user);user = null;}currentTag = null;

    ?重寫endDocument,這里直接給個空實現(xiàn),我們只需觀察Log輸出

    Log.e("endDocument", "-endDocument()");

    XmlParseHandler.java完整代碼:

    package com.example.saxparsexmldemo;import java.util.ArrayList; import java.util.List;import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;import android.util.Log;public class XmlParseHandler extends DefaultHandler {private List<User> users;private String currentTag; // 記錄當前解析到的節(jié)點名稱private User user; // 記錄當前的user/*** 文檔解析結束后調(diào)用*/@Overridepublic void endDocument() throws SAXException {super.endDocument();Log.e("endDocument", "-endDocument()");}/*** 節(jié)點解析結束后調(diào)用* @param uri : 命名空間的uri* @param localName : 標簽的名稱* @param qName : 帶命名空間的標簽名稱*/@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {super.endElement(uri, localName, qName);Log.e("endElement", localName + "-endElement()");if("user".equals(localName)){users.add(user);user = null;}currentTag = null;}/*** 文檔解析開始調(diào)用*/@Overridepublic void startDocument() throws SAXException {super.startDocument();Log.e("startDocument", "startDocument()");users = new ArrayList<User>();}/*** 節(jié)點解析開始調(diào)用* @param uri : 命名空間的uri* @param localName : 標簽的名稱* @param qName : 帶命名空間的標簽名稱*/@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {super.startElement(uri, localName, qName, attributes);Log.e("startElement", localName + "-startElement()");if ("user".equals(localName)) { // 是一個用戶for (int i = 0; i < attributes.getLength(); i++) {Log.e("attributes", "attribute_name:" + attributes.getLocalName(i)+ " attribute_value:" + attributes.getValue(i));user = new User();if("id".equals(attributes.getLocalName(i))){user.setId(Long.parseLong(attributes.getValue(i)));}}}currentTag = localName; // 把當前標簽記錄下來}@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {super.characters(ch, start, length); String value = new String(ch,start,length); // 將當前TextNode轉換為StringLog.e("characters", value+"");if("name".equals(currentTag)){ // 當前標簽為name標簽,該標簽無子標簽,直接將上面獲取到的標簽的值封裝到當前User對象中// 該節(jié)點為name節(jié)點user.setName(value);}else if("password".equals(currentTag)){ // 當前標簽為password標簽,該標簽無子標簽,直接將上面獲取到的標簽的值封裝到當前User對象中// 該節(jié)點為password節(jié)點user.setPassword(value);}}public List<User> getUsers() {return users;} }

    4、新建一個類XmlParseUtils.java,寫一個方法進行xml解析

    public static List<User> getUsers() throws ParserConfigurationException, SAXException, IOException {// 加載文件返回文件的輸入流InputStream is = XmlParseUtils.class.getClassLoader().getResourceAsStream("users.xml");XmlParseHandler handler = new XmlParseHandler();// 1. 得到SAX解析工廠SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();// 2. 讓工廠生產(chǎn)一個sax解析器SAXParser newSAXParser = saxParserFactory.newSAXParser();// 3. 傳入輸入流和handler,解析newSAXParser.parse(is, handler);is.close();return handler.getUsers();}

    ?其中第三步也可以通過XMLReader來完成

    XMLReader xmlReader = newSAXParser.getXMLReader(); InputSource input = new InputSource(is); xmlReader.parse(input );

    到這里SAX解析XML的代碼完成了,OK,萬事具備,只欠測試了

    這里我們用Android的單元測試,只需完成調(diào)用XmlParseUtilsgetUsers()方法測試輸出即可

    Android的單元測試(需要連接模擬器或者手機)
    • 環(huán)境搭建

      • 在 AndroidManifest.xml的根節(jié)點下面添加一個instrumentation

        <instrumentation android:targetPackage="com.example.saxparsexmldemo" android:name="android.test.InstrumentationTestRunner"></instrumentation>
      • 在 AndroidManifest.xml的application節(jié)點下面添加uses-library

        <uses-library android:name="android.test.runner"/>

    • 在com.example.saxparsexmldemo下面新建一個測試類SAXParseXmlTest.java,寫一個測試方法
    public void testSAXgetUsers() throws Exception{List<User> users = XmlParseUtils.getUsers();for(User user : users){Log.e(TAG, "name:"+user.getName());Log.e(TAG, "password:"+user.getPassword());}}

    ?OK,右鍵該類的testSAXgetUsers,Run As Android JUnit Test,我們可以看到XML解析成功

    通過上面的這個小Demo的完成,我們可以看到SAX解析代碼不多也不難理解,關鍵是Handler的幾個方法的使用,即遇到什么符號會觸發(fā)什么事件,以及觸發(fā)過程,掌握了SAX的事件觸發(fā),那么就掌握了SAX解析XML,下面我們來分析一下SAX解析的原理或流程

    四、SAX解析XML原理

    在分析SAX解析原理之前,我們先看一下上面的demo的日志輸出

    以users.xml的解析過程為例,結合上面的日志輸出,我們可以分析出SAX解析的流程

    1、xml解析開始,startDocument被調(diào)用,這個方法在整個xml解析過程中調(diào)用了一次,所以我們可以在這個方法里面初為解析XML做一些準備,比如初始化變量?
    2、解析每遇到一個標簽都會經(jīng)歷startElement-characters-endElement這個過程,即每一個標簽都會觸發(fā)startElement-characters-endElement?
    3、通過users這個根節(jié)點的解析,user標簽解析以及name,password標簽解析過程,我們知道user標簽是users的子標簽,name和password標簽是user標簽的子標簽,我們知道當解析一個標簽的時候,如果該標簽有子標簽,則先回調(diào)用該標簽的startElement方法,這里面可以先得到該標簽的屬性信息,然后觸發(fā)characters解析該標簽的內(nèi)容(值),然后子標簽觸發(fā)startElement-characters-endElement(子標簽觸發(fā)),最后該標簽觸發(fā)endElement,該標簽解析結束

    下面畫一個圖讓我們進一步理解SAX解析XML的原理:

    對上圖做個簡單說明,當當前標簽有子標簽的時候,該標簽先觸發(fā)characters,然后子標簽觸發(fā)startElement-characters-endElement事件,這個過程可以理解為一個不斷遞歸的過程。

    OK,SAX解析原理分析完了,最后用一句話描述SAX解析過程

    startDocument-startElement-characters-endElement-endDocument

    總結,SAX解析XML具有解析速度快,占用內(nèi)存少,對于Android等移動設備來說有巨大的優(yōu)勢,深入了解SAX的事件觸發(fā)機制是掌握SAX解析的關鍵,掌握了SAX的事件觸發(fā)就掌握了SAX解析XML

    上面這篇文章由于個人理解,如果有理解錯的地方,歡迎大家指出,與君共勉,一起進步。

    Demo下載地址:http://download.csdn.net/detail/ydxlt/9328309

    下篇文章:【XML解析(二)】DOM解析XML


    總結

    以上是生活随笔為你收集整理的XML解析(一),SAX解析XML的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。