Home | History | Annotate | Download | only in networkusage
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package com.example.android.networkusage;
     16 
     17 import android.util.Xml;
     18 
     19 import org.xmlpull.v1.XmlPullParser;
     20 import org.xmlpull.v1.XmlPullParserException;
     21 
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 
     27 /**
     28  * This class parses XML feeds from stackoverflow.com.
     29  * Given an InputStream representation of a feed, it returns a List of entries,
     30  * where each list element represents a single entry (post) in the XML feed.
     31  */
     32 public class StackOverflowXmlParser {
     33     private static final String ns = null;
     34 
     35     // We don't use namespaces
     36 
     37     public List<Entry> parse(InputStream in) throws XmlPullParserException, IOException {
     38         try {
     39             XmlPullParser parser = Xml.newPullParser();
     40             parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
     41             parser.setInput(in, null);
     42             parser.nextTag();
     43             return readFeed(parser);
     44         } finally {
     45             in.close();
     46         }
     47     }
     48 
     49     private List<Entry> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
     50         List<Entry> entries = new ArrayList<Entry>();
     51 
     52         parser.require(XmlPullParser.START_TAG, ns, "feed");
     53         while (parser.next() != XmlPullParser.END_TAG) {
     54             if (parser.getEventType() != XmlPullParser.START_TAG) {
     55                 continue;
     56             }
     57             String name = parser.getName();
     58             // Starts by looking for the entry tag
     59             if (name.equals("entry")) {
     60                 entries.add(readEntry(parser));
     61             } else {
     62                 skip(parser);
     63             }
     64         }
     65         return entries;
     66     }
     67 
     68     // This class represents a single entry (post) in the XML feed.
     69     // It includes the data members "title," "link," and "summary."
     70     public static class Entry {
     71         public final String title;
     72         public final String link;
     73         public final String summary;
     74 
     75         private Entry(String title, String summary, String link) {
     76             this.title = title;
     77             this.summary = summary;
     78             this.link = link;
     79         }
     80     }
     81 
     82     // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them
     83     // off
     84     // to their respective &quot;read&quot; methods for processing. Otherwise, skips the tag.
     85     private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
     86         parser.require(XmlPullParser.START_TAG, ns, "entry");
     87         String title = null;
     88         String summary = null;
     89         String link = null;
     90         while (parser.next() != XmlPullParser.END_TAG) {
     91             if (parser.getEventType() != XmlPullParser.START_TAG) {
     92                 continue;
     93             }
     94             String name = parser.getName();
     95             if (name.equals("title")) {
     96                 title = readTitle(parser);
     97             } else if (name.equals("summary")) {
     98                 summary = readSummary(parser);
     99             } else if (name.equals("link")) {
    100                 link = readLink(parser);
    101             } else {
    102                 skip(parser);
    103             }
    104         }
    105         return new Entry(title, summary, link);
    106     }
    107 
    108     // Processes title tags in the feed.
    109     private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
    110         parser.require(XmlPullParser.START_TAG, ns, "title");
    111         String title = readText(parser);
    112         parser.require(XmlPullParser.END_TAG, ns, "title");
    113         return title;
    114     }
    115 
    116     // Processes link tags in the feed.
    117     private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
    118         String link = "";
    119         parser.require(XmlPullParser.START_TAG, ns, "link");
    120         String tag = parser.getName();
    121         String relType = parser.getAttributeValue(null, "rel");
    122         if (tag.equals("link")) {
    123             if (relType.equals("alternate")) {
    124                 link = parser.getAttributeValue(null, "href");
    125                 parser.nextTag();
    126             }
    127         }
    128         parser.require(XmlPullParser.END_TAG, ns, "link");
    129         return link;
    130     }
    131 
    132     // Processes summary tags in the feed.
    133     private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
    134         parser.require(XmlPullParser.START_TAG, ns, "summary");
    135         String summary = readText(parser);
    136         parser.require(XmlPullParser.END_TAG, ns, "summary");
    137         return summary;
    138     }
    139 
    140     // For the tags title and summary, extracts their text values.
    141     private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
    142         String result = "";
    143         if (parser.next() == XmlPullParser.TEXT) {
    144             result = parser.getText();
    145             parser.nextTag();
    146         }
    147         return result;
    148     }
    149 
    150     // Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
    151     // if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
    152     // finds the matching END_TAG (as indicated by the value of "depth" being 0).
    153     private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
    154         if (parser.getEventType() != XmlPullParser.START_TAG) {
    155             throw new IllegalStateException();
    156         }
    157         int depth = 1;
    158         while (depth != 0) {
    159             switch (parser.next()) {
    160             case XmlPullParser.END_TAG:
    161                     depth--;
    162                     break;
    163             case XmlPullParser.START_TAG:
    164                     depth++;
    165                     break;
    166             }
    167         }
    168     }
    169 }
    170