<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                > 編寫:[kesenhoo](https://github.com/kesenhoo) - 原文:[http://developer.android.com/training/basics/network-ops/xml.html](http://developer.android.com/training/basics/network-ops/xml.html) Extensible Markup Language (XML) 是一組將文檔編碼成機器可讀形式的規則,也是一種在網絡上共享數據的普遍格式。經常更新內容的網站比如新聞網站和博客上都提供XML feed來記錄更新的信息,以便用戶進行訂閱讀取。 上傳[?]與解析XML數據是app的一個常見的功能。 這一課會介紹如何解析XML文檔并使用他們的數據。 _([?]這里很奇怪,為什么是Upload,看文章最后一段代碼示例的注釋,應該是Download才對)_ **示例**:[NetworkUsage.zip](http://developer.android.com/shareables/training/NetworkUsage.zip) ### 1)選擇一個Parser 我們推薦[XmlPullParser](http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html), 它是在Android上一個高效且可維護的解析XML方法。 Android 上有這個接口的兩種實現方式: - [KXmlParser](http://kxml.sourceforge.net/),通過 [XmlPullParserFactory.newPullParser()](http://developer.android.com/reference/org/xmlpull/v1/XmlPullParserFactory.html#newPullParser())得到. - ExpatPullParser,通過[Xml.newPullParser()](http://developer.android.com/reference/android/util/Xml.html#newPullParser())得到. 兩個選擇都是比較好的。下面的示例中是使用ExpatPullParser,通過Xml.newPullParser()得到. ### 2)分析Feed 解析一個feed的第一步是決定你需要獲取的字段。這樣解析器便去抽取出那些需要的字段而忽視其他的字段。 下面的XML片段是章節概覽Sample app中解析的Feed的片段。[StackOverflow](http://stackoverflow.com/)上每一個帖子都在feed中以時包含幾個嵌套的子標簽(tag)的entry標簽的形式出現。 ~~~ <?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> ~~~ Sample app從entry標簽與它的子標簽title,link和summary中提取數據. ### 3)實例化Parser 下一步就是實例化一個parser并開始解析的操作。在下面的片段中,一個parser被初始化來處理名稱空間,并且將[InputStream](http://developer.android.com/reference/java/io/InputStream.html)作為輸入。它通過調用[nextTag()](http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html#nextTag())開始解析,并調用 readFeed() 方法,readFeed()方法會提取并處理app需要的數據: ~~~ public class StackOverflowXmlParser { // We don't use namespaces 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(); } } ... } ~~~ ### 4)讀取Feed readFeed() 方法實際上并沒有處理feed的內容。它只是在尋找一個 "entry" 的標簽作為遞歸(recursively)處理整個feed的起點。 readFeed()方法會跳過不是"entry"的標簽。當整個feed都被遞歸處理后,readFeed() 會返回一個從feed中提取的包含了entry標簽(包括里面的數據成員)的 [List](http://developer.android.com/reference/java/util/List.html)。然后這個[List](http://developer.android.com/reference/java/util/List.html)成為parser的返回值。 ~~~ 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; } ~~~ ### 5)解析XML 解析步驟如下: - 正如在上面“ 分析Feed”所說的, 判斷出你想要的tag。這個example抽取了 entry 標簽與它的內部標簽 title,link,summary中的數據. - 創建下面的方法: - 為每一個你想要獲取的標簽創建一個 "read" 方法。例如 readEntry(), readTitle() 等等. 解析器從input stream中讀取tag . 當讀取到 entry, title, link 或者 summary 標簽時,它會為那些標簽調用相應的方法,否則,跳過這個標簽。 - 為每一個不同的標簽創建提取數據的方法,和使parser繼續解析下一個tag的方法。例如: - 對于 title 和 summary 標簽, 解析器調用 readText(). 這個方法通過調用parser.getText()來獲取數據。 - 對于 link 標簽,解析器先判斷這個link是否是我們想要的類型,然后再讀取數據。使用 parser.getAttributeValue() 來獲取link的數據。 - 對于 entry 標簽, 解析起調用 readEntry(). 這個方法解析entry的內部標簽并返回一個帶有title, link 和 summary數據成員的Entry對象。 - 一個遞歸的輔助方法:skip() . 關于這部分的討論,請看下面一部分內容:跳過你不需要的tag 下面的代碼演示了如何解析 entries, titles, links 與 summaries. ~~~ 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; } ... } ~~~ ### 6)跳過你不需要的tag 上面描述的XML解析步驟中有一步就是跳過不需要的tag,下面演示解析器的 skip() 方法: ~~~ 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; } } } ~~~ 下面解釋這個方法如何工作: - 如果下一個標簽不是一個 START_TAG (開始標簽),拋出異常。 - 它消耗掉 START_TAG 以及接下來的所有內容,包括與開始標簽配對的 END_TAG (結束標簽). - 為了保證方法在遇到正確的 END_TAG 時停止,方法隨時記錄嵌套深度。 因此如果目前的標簽有子標簽, 直到解析器已經處理了所有位于START_TAG與對應的END_TAG之間的事件之前,depth 的值不會為 0。例如,看解析器如何跳過 `<author>` 標簽,它有2個子標簽,`<name>` 與 `<uri>`: - 第一次循環, 在‘’之后parser遇到的第一個標簽是 START_TAG `<name>`. depth值變為2. - 第二次循環, parser遇到的下一個標簽是 END_TAG `</name>`. depth值變為1. - 第三次循環, parser遇到的下一個標簽是 START_TAG `<uri>`. depth值變為2. - 第四次循環, parser遇到的下一個標簽是 END_TAG `</uri>`. depth值變為1. - 第五次同時也是最后一次循環, parser遇到的下一個標簽是 END_TAG `</author>`. depth值變為0, 表明成功跳過了`<author>`標簽. ### 6)使用XML數據 示例程序是在 [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) 中獲取與解析XML數據的。這樣處理工程不會在UI線程中執行。當處理完畢后,app會更新main [activity](# "An activity represents a single screen with a user interface.")(NetworkActivity)的UI。 在下面示例代碼中,loadPage() 方法做了下面的事情: - 初始化一個帶有URL地址的String變量,用來訂閱XML feed。 - 如果用戶設置與網絡連接都允許,會觸發 new DownloadXmlTask().execute(url). 這會初始化一個新的 DownloadXmlTask ( [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) 的子類) 對象并且開始執行它的 [execute()](http://developer.android.com/reference/android/os/AsyncTask.html#execute(Params...)) 方法,這個方法會下載并解析feed,并返回結果字符串展示在UI上。 ~~~ public class NetworkActivity extends Activity { public static final String WIFI = "Wi-Fi"; public static final String ANY = "Any"; private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest"; // Whether there is a Wi-Fi connection. private static boolean wifiConnected = false; // Whether there is a mobile connection. private static boolean mobileConnected = false; // Whether the display should be refreshed. public static boolean refreshDisplay = true; public static String sPref = null; ... // Uses AsyncTask to download the XML feed from stackoverflow.com. public void loadPage() { if((sPref.equals(ANY)) && (wifiConnected || mobileConnected)) { new DownloadXmlTask().execute(URL); } else if ((sPref.equals(WIFI)) && (wifiConnected)) { new DownloadXmlTask().execute(URL); } else { // show error } } ~~~ 下面展示的是 [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) 的子類,DownloadXmlTask實現了 [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) 的如下方法: - [doInBackground()](http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground(Params...)) 執行 loadXmlFromNetwork() 方法。它以feed的URL作為參數。loadXmlFromNetwork()獲取并處理feed。當它完成時,返回一個結果字符串。 - [onPostExecute()](http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)) 接受返回的字符串并將其展示在UI上. ~~~ // Implementation of AsyncTask used to download XML feed from stackoverflow.com. private class DownloadXmlTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... urls) { try { return loadXmlFromNetwork(urls[0]); } catch (IOException e) { return getResources().getString(R.string.connection_error); } catch (XmlPullParserException e) { return getResources().getString(R.string.xml_error); } } @Override protected void onPostExecute(String result) { setContentView(R.layout.main); // Displays the HTML string in the UI via a WebView WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadData(result, "text/html", null); } } ~~~ 下面是loadXmlFromNetwork()方法做的事情: 1. 實例化一個StackOverflowXmlParser. 它同樣創建一個`List<Entry>`,Entry對象包括title, url, summary字段來保存從XML feed中提取的數據. 1. 調用 downloadUrl() , 它會獲取feed, 并將其作為 [InputStream](http://developer.android.com/reference/java/io/InputStream.html) 返回. 1. 使用 StackOverflowXmlParser 解析 [InputStream](http://developer.android.com/reference/java/io/InputStream.html) . StackOverflowXmlParser 用從feed中獲取的數據填充`List<Entry>`. 1. 處理 `List<Entry>` , 將feed數據與HTML標記結合起來. 1. 返回一個HTML字符串, [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) 的方法 [onPostExecute()](http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)) 會將其展示在main [activity](# "An activity represents a single screen with a user interface.")的UI上. ~~~ // Uploads XML from stackoverflow.com, parses it, and combines it with // HTML markup. Returns HTML string.【這里可以看出應該是Download】 private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException { InputStream stream = null; // Instantiate the parser StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser(); List<Entry> entries = null; String title = null; String url = null; String summary = null; Calendar rightNow = Calendar.getInstance(); DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa"); // Checks whether the user set the preference to include summary text SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); boolean pref = sharedPrefs.getBoolean("summaryPref", false); StringBuilder htmlString = new StringBuilder(); htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>"); htmlString.append("<em>" + getResources().getString(R.string.updated) + " " + formatter.format(rightNow.getTime()) + "</em>"); try { stream = downloadUrl(urlString); entries = stackOverflowXmlParser.parse(stream); // Makes sure that the InputStream is closed after the app is // finished using it. } finally { if (stream != null) { stream.close(); } } // StackOverflowXmlParser returns a List (called "entries") of Entry objects. // Each Entry object represents a single post in the XML feed. // This section processes the entries list to combine each entry with HTML markup. // Each entry is displayed in the UI as a link that optionally includes // a text summary. for (Entry entry : entries) { htmlString.append("<p><a href='"); htmlString.append(entry.link); htmlString.append("'>" + entry.title + "</a></p>"); // If the user set the preference to include summary text, // adds it to the display. if (pref) { htmlString.append(entry.summary); } } return htmlString.toString(); } // Given a string representation of a URL, sets up a connection and gets // an input stream. 【關于Timeout具體應該設置多少,可以借鑒這里的數據,當然前提是一般情況下】 // Given a string representation of a URL, sets up a connection and gets // an input stream. private InputStream downloadUrl(String urlString) throws IOException { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000 /* milliseconds */); conn.setConnectTimeout(15000 /* milliseconds */); conn.setRequestMethod("GET"); conn.setDoInput(true); // Starts the query conn.connect(); return conn.getInputStream(); } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看