欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android開發(fā)筆記XML數(shù)據(jù)解析方法及優(yōu)缺點(diǎn)

 更新時(shí)間:2023年05月09日 09:06:02   作者:Tai_Monster  
XML數(shù)據(jù)是一種常見的數(shù)據(jù)格式,Android開發(fā)中需要對(duì)其進(jìn)行解析。常用的XML解析方式有DOM、SAX、Pull和Json等,每種方式都有其優(yōu)缺點(diǎn)。開發(fā)者可以根據(jù)具體需求選擇合適的解析方式,提高數(shù)據(jù)解析效率和性能

何為XML數(shù)據(jù)

XML 指可擴(kuò)展標(biāo)記語(yǔ)言(eXtensible Markup Language)。

可擴(kuò)展標(biāo)記語(yǔ)言(英語(yǔ):Extensible Markup Language,簡(jiǎn)稱:XML)是一種標(biāo)記語(yǔ)言,是從標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言(SGML)中簡(jiǎn)化修改出來(lái)的。 其最主要的功能就是為了方便數(shù)據(jù)的傳輸與交換。

在Android開發(fā)中,我們有時(shí)候也需要從服務(wù)器上獲取xml數(shù)據(jù)并加以解析

如何解析XML數(shù)據(jù)

1.Pull解析

這里我們根據(jù)谷歌官方的開發(fā)者文檔提供的方法,也是其推薦的方法來(lái)解析xml數(shù)據(jù)。

1.分析Feed中感興趣的標(biāo)簽內(nèi)容

例如:

  <?xml version="1.0" encoding="utf-8"?>
  <feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" ...">
  <title type="text">newest questions tagged android - Stack Overflow</title>
  ...
      <entry>
      ...
      </entry>
      <entry>
          <id>http://stackoverflow.com/q/9439999</id>
          <re:rank scheme="http://stackoverflow.com">0</re:rank>
          <title type="text">Where is my data file?</title>
          <category scheme="http://stackoverflow.com/feeds/tag?
          tagnames=android&sort=newest/tags" term="android"/>
          <category scheme="http://stackoverflow.com/feeds/tag?
          tagnames=android&sort=newest/tags" term="file"/>
          <author>
              <name>cliff2310</name>
              <uri>http://stackoverflow.com/users/1128925</uri>
          </author>
          <link rel="alternate" href="http://stackoverflow.com/
          questions/9439999/where-is-my-data-file" />
          <published>2012-02-25T00:30:54Z</published>
          <updated>2012-02-25T00:30:54Z</updated>
          <summary type="html">
              <p>I have an Application that requires a data 
              file...</p>
          </summary>
      </entry>
      <entry>
      ...
      </entry>
  ...
  </feed>

就是一份xml數(shù)據(jù),其中兩個(gè)對(duì)應(yīng)<>中的內(nèi)容即為一個(gè)標(biāo)簽中的內(nèi)容,比如說(shuō)entry標(biāo)簽中嵌套的id標(biāo)簽為:

<id>http://stackoverflow.com/q/9439999</id>

其內(nèi)容即為http://stackoverflow.com/q/9439999

2.選擇解析器

為了解析xml數(shù)據(jù),我們需要選擇一些解析器來(lái)幫助我們分析數(shù)據(jù)。

官方文檔中提到:

  XmlPullParser,這是一種在 Android 上解析 XML 的高效且可維護(hù)的方式。以前,Android 有此接口的兩個(gè)實(shí)現(xiàn):

  KXmlParser(通過(guò) XmlPullParserFactory.newPullParser())。  

ExpatPullParser(通過(guò) Xml.newPullParser())。

  任一選擇都可以。此部分中的示例使用 ExpatPullParser(通過(guò) Xml.newPullParser())。

3.實(shí)例化解析器

前文提到過(guò),有具體的兩種方式實(shí)例化解析器,分別是 用工廠類生成 或者 直接用實(shí)例生成。比如:

  //工廠類生成:
      XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
      XmlPullParser xmlPullParser = factory.newPullParser();        
  //實(shí)例生成:
      XmlPullParser xmlPullParser = Xml.newPullParser();

兩者任選其一即可。

4.然后我們可以具體配置一下解析器

     public class StackOverflowXmlParser {
     private static final String ns = null;
     public List parse(InputStream in) throws XmlPullParserException, IOException {
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setFeature(XmlPullParser.
             FEATURE_PROCESS_NAMESPACES, false);
             parser.setInput(in, null);
             parser.nextTag();
             return readFeed(parser);
         } finally {
             in.close();
         }
      }
         ...
     }

其中,parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);這一行是用來(lái)禁用名稱空間的,當(dāng)然setFeature方法還可以用來(lái)配置解析器的其他一些參數(shù),可以查看官方的文檔。

parser.setInput(in, null);是設(shè)置了具體的數(shù)據(jù)流和編碼格式,如果設(shè)置為null則使用系統(tǒng)默認(rèn)的編碼。此處還可以只設(shè)置一個(gè)字節(jié)流(Reader),比如:

xmlPullParser.setInput(new StringReader(xmlData));

parser.nextTag();調(diào)用 nextTag() 開始解析過(guò)程 ,官方的文檔里是這樣描述的:

Call next() and return event if it is START_TAG or END_TAG otherwise throw an exception. It will skip whitespace TEXT before actual tag if any.

就是說(shuō),如果是START_TAG或END_TAG,則調(diào)用next()并返回事件,否則拋出異常。它將跳過(guò)實(shí)際標(biāo)記之前的空白TEXT(如果有的話)。本質(zhì)代碼:

      int eventType = next();
     if(eventType == TEXT &&  isWhitespace()) {   // skip whitespace
         eventType = next();
     }
     if (eventType != START_TAG &&  eventType != END_TAG) {
         throw new XmlPullParserException("expected start or end 
         tag", this, null);
     }
     return eventType;

next()方法則是用來(lái)獲取下一個(gè)解析事件的。

5.創(chuàng)建具體的方法來(lái)解析數(shù)據(jù)

  private List readFeed(XmlPullParser parser) throws 
  XmlPullParserException, IOException {
  List entries = new ArrayList();
  parser.require(XmlPullParser.START_TAG, ns, "feed");
  while (parser.next() != XmlPullParser.END_TAG) {
          if (parser.getEventType() != XmlPullParser.START_TAG) {
              continue;
          }
          String name = parser.getName();
          // Starts by looking for the entry tag
          if (name.equals("entry")) {
              entries.add(readEntry(parser));
          } else {
              skip(parser);
          }
      }
      return entries;
  }

這里一開始的require方法是用來(lái)測(cè)試條件的,它接受三個(gè)參數(shù),分別是預(yù)期的事件類型,名稱空間,名稱。

它將測(cè)試當(dāng)前事件是否屬于給定的類型,以及名稱空間和名稱是否匹配。Null將匹配任何名稱空間和任何名稱。如果測(cè)試未通過(guò),則拋出異常。異常文本指示解析器位置、預(yù)期事件和不滿足需求的當(dāng)前事件。

這里的next事件可能返回的兩個(gè)值,XmlPullParser.START_TAG 和 XmlPullParser.END_TAG 分別對(duì)應(yīng)的是開始解析一個(gè)節(jié)點(diǎn)和完成一個(gè)節(jié)點(diǎn)的解析的標(biāo)志。還有一個(gè)重要的標(biāo)志是XmlPullParser.END_DOCUMENT,對(duì)應(yīng)的是解析工作完成。

skip函數(shù)則是用來(lái)跳過(guò)不感興趣的標(biāo)簽的。

  private void skip(XmlPullParser parser) throws 
  XmlPullParserException, IOException {
  if (parser.getEventType() != XmlPullParser.START_TAG) {
      throw new IllegalStateException();
  }
  int depth = 1;
  while (depth != 0) {
      switch (parser.next()) {
      case XmlPullParser.END_TAG:
          depth--;
          break;
      case XmlPullParser.START_TAG:
          depth++;
          break;
      }
  }
}

接下來(lái)則會(huì)進(jìn)入到entry標(biāo)簽中進(jìn)行進(jìn)一步的解析:

  public static class Entry {
  public final String title;
  public final String link;
  public final String summary;
  private Entry(String title, String summary, String link) {
      this.title = title;
      this.summary = summary;
      this.link = link;
  }
 }
  // Parses the contents of an entry. If it encounters a title,
   summary, or link tag, hands them off
  // to their respective "read" methods for processing. 
  Otherwise, skips the tag.
  private Entry readEntry(XmlPullParser parser) throws 
  XmlPullParserException, IOException {
      parser.require(XmlPullParser.START_TAG, ns, "entry");
      String title = null;
      String summary = null;
      String link = null;
      while (parser.next() != XmlPullParser.END_TAG) {
          if (parser.getEventType() != XmlPullParser.START_TAG) {
              continue;
          }
          String name = parser.getName();
          if (name.equals("title")) {
              title = readTitle(parser);
          } else if (name.equals("summary")) {
              summary = readSummary(parser);
          } else if (name.equals("link")) {
              link = readLink(parser);
          } else {
              skip(parser);
          }
      }
      return new Entry(title, summary, link);
  }
  // Processes title tags in the feed.
  private String readTitle(XmlPullParser parser) throws 
  IOException, XmlPullParserException {
      parser.require(XmlPullParser.START_TAG, ns, "title");
      String title = readText(parser);
      parser.require(XmlPullParser.END_TAG, ns, "title");
      return title;
  }
  // Processes link tags in the feed.
  private String readLink(XmlPullParser parser) throws 
  IOException, XmlPullParserException {
      String link = "";
      parser.require(XmlPullParser.START_TAG, ns, "link");
      String tag = parser.getName();
      String relType = parser.getAttributeValue(null, "rel");
      if (tag.equals("link")) {
          if (relType.equals("alternate")){
              link = parser.getAttributeValue(null, "href");
              parser.nextTag();
          }
      }
      parser.require(XmlPullParser.END_TAG, ns, "link");
      return link;
  }
  // Processes summary tags in the feed.
  private String readSummary(XmlPullParser parser) throws 
  IOException, XmlPullParserException {
      parser.require(XmlPullParser.START_TAG, ns, "summary");
      String summary = readText(parser);
      parser.require(XmlPullParser.END_TAG, ns, "summary");
      return summary;
  }
  // For the tags title and summary, extracts their text values.
  private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
      String result = "";
      if (parser.next() == XmlPullParser.TEXT) {
          result = parser.getText();
          parser.nextTag();
      }
      return result;
  }
  ...
  }

這里官方示例寫的比較復(fù)雜,但是模塊化做的較好。這里創(chuàng)建了一個(gè)靜態(tài)內(nèi)部類Entry來(lái)輔助組織并返回?cái)?shù)據(jù)。 首先開始讀取后利用getName()方法來(lái)獲取節(jié)點(diǎn)的名稱,對(duì)于每個(gè)具體的節(jié)點(diǎn),也分別寫了不同的方法來(lái)讀取。

  • 我們首先來(lái)看最基本的讀取方法readText方法,這實(shí)際上是對(duì)解析器提供的getText方法的封裝,當(dāng)解析的下一個(gè)事件為TEXT時(shí),即利用getText方法將其內(nèi)容返回出去。
  • 接著其實(shí)其他的解析方法都大同小異,但都要根據(jù)標(biāo)簽內(nèi)部具體的內(nèi)容來(lái)設(shè)計(jì)具體的解析邏輯,比如實(shí)例中比較特殊的readLink方法,其中有一個(gè)getAttributeValue方法,是根據(jù)名稱空間和具體的屬性名稱來(lái)獲取屬性值的,

比如上面的代碼:

String relType = parser.getAttributeValue(null, “rel”);

就是設(shè)置無(wú)名稱空間,獲取了Link標(biāo)簽里rel的具體的值。

然后再根據(jù)rel的值來(lái)決定是否解析href的值。

2.簡(jiǎn)單的Pull解析

上面的Pull解析未免太過(guò)繁瑣,在Android第一行代碼中也有較為簡(jiǎn)單的解析:

要解析的數(shù)據(jù):

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

具體的解析方法:

private void parseXMLWithPull(String xmlData){
    try{
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        XmlPullParser xmlPullParser = factory.newPullParser();
        xmlPullParser.setInput(new StringReader(xmlData));
        int eventType = xmlPullParser.getEventType();
        String id = "";
        String name = "";
        String version = "";
        while(eventType != XmlPullParser.END_DOCUMENT){
            String nodeName = xmlPullParser.getName();
            switch (eventType){
                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;
            }
            eventType = xmlPullParser.next();
        }
    }catch (Exception e){
        e.printStackTrace();
    }
}   

這里省去了一些繁瑣的檢測(cè),名稱空間的設(shè)置等,并且用XmlPullParser.END_DOCUMENT作為判斷解析事件是否完成的標(biāo)志。

3.SAX解析

SAX解析與Pull解析類似,是由事件驅(qū)動(dòng)的。其采用流式解析,解析與讀取同步,讀到哪就解析到哪。

要用SAX解析,我們就需要用到接口ContentHandle,一般情況下,我們可以繼承系統(tǒng)自帶的DefaultDocument,并且重寫其中的五個(gè)方法。

這里我們解析上面2中簡(jiǎn)單Pull解析中的數(shù)據(jù),重寫DefaultHandle類:

public class MyHandle extends DefaultHandler {
private final String TAG = "MainActivity";
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
@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{
    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(TAG,"id is "+ id.toString().trim());
        Log.d(TAG,"name is "+name.toString().trim());
        Log.d(TAG,"version is "+version.toString().trim());
        id.setLength(0);
        name.setLength(0);
        version.setLength(0);
    }
}
@Override
public void endDocument() throws  SAXException{
    super.endDocument();
 }
}

SAX解析類似于觸發(fā)器,每個(gè)方法都會(huì)在一個(gè)特定的時(shí)候被調(diào)用,startDocument方法

會(huì)在開始解析任務(wù)時(shí)執(zhí)行,startElement方法會(huì)在開始解析一個(gè)節(jié)點(diǎn)時(shí)執(zhí)行,characters是具體解析節(jié)點(diǎn)的過(guò)程,endElement方法會(huì)在一個(gè)節(jié)點(diǎn)解析完成時(shí)執(zhí)行,endDocument方法會(huì)在整個(gè)解析過(guò)程完成后執(zhí)行。

總的來(lái)說(shuō),SAX解析的模版比較固定,語(yǔ)義也比較清晰。

到此這篇關(guān)于Android開發(fā)筆記XML數(shù)據(jù)解析方法及優(yōu)缺點(diǎn)的文章就介紹到這了,更多相關(guān)Android XML數(shù)據(jù)解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Kotlin學(xué)習(xí)教程之協(xié)程Coroutine

    Kotlin學(xué)習(xí)教程之協(xié)程Coroutine

    這篇文章主要給大家介紹了關(guān)于Kotlin學(xué)習(xí)教程之協(xié)程Coroutine的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • Android發(fā)送GET與POST請(qǐng)求的DEMO詳解

    Android發(fā)送GET與POST請(qǐng)求的DEMO詳解

    本篇文章是對(duì)Android發(fā)送GET與POST請(qǐng)求的DEMO進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Android Service判斷設(shè)備聯(lián)網(wǎng)狀態(tài)詳解

    Android Service判斷設(shè)備聯(lián)網(wǎng)狀態(tài)詳解

    本文主要介紹Android Service判斷聯(lián)網(wǎng)狀態(tài),這里提供了相關(guān)資料并附有示例代碼,有興趣的小伙伴可以參考下,幫助開發(fā)相關(guān)應(yīng)用功能
    2016-08-08
  • Android編程實(shí)現(xiàn)TextView部分顏色變動(dòng)的方法

    Android編程實(shí)現(xiàn)TextView部分顏色變動(dòng)的方法

    這篇文章主要介紹了Android編程實(shí)現(xiàn)TextView部分顏色變動(dòng)的方法,實(shí)例分析了TextView設(shè)置指定位置的背景色與字體顏色的相關(guān)技巧,需要的朋友可以參考下
    2015-12-12
  • AccessibilityService實(shí)現(xiàn)微信發(fā)紅包功能

    AccessibilityService實(shí)現(xiàn)微信發(fā)紅包功能

    這篇文章主要為大家詳細(xì)介紹了AccessibilityService實(shí)現(xiàn)微信發(fā)紅包功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 給Android初學(xué)者的Gradle知識(shí)普及

    給Android初學(xué)者的Gradle知識(shí)普及

    剛學(xué) Android 不久,對(duì) Gradle 不懂,看了很多資料依然一知半解,很多人都這樣覺(jué)得,表示同感,下面小編來(lái)給大家講講 Gradle相關(guān)知識(shí),需要的朋友跟隨小編一起來(lái)學(xué)習(xí)一下
    2018-09-09
  • Android studio 混淆配置詳解

    Android studio 混淆配置詳解

    這篇文章主要介紹了Android studio 混淆配置詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Ubuntu Android源碼以及內(nèi)核下載與編譯

    Ubuntu Android源碼以及內(nèi)核下載與編譯

    本文主要介紹Android源碼的下載和編譯,這里整理了相關(guān)資料及如何下載和編譯的詳細(xì)步驟,有需要的小伙伴可以參考下
    2016-09-09
  • Android開發(fā)保存QQ密碼功能

    Android開發(fā)保存QQ密碼功能

    這篇文章主要為大家詳細(xì)介紹了Android開發(fā)保存QQ密碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • android中webview定位問(wèn)題示例詳解

    android中webview定位問(wèn)題示例詳解

    這篇文章主要給大家介紹了關(guān)于android中webview定位問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12

最新評(píng)論