/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ /*OOBD Bugs is just a small modification of the Network usage sample given at http://developer.android.com/training/basics/network-ops/xml.html */ package org.oobd.tools.oobdbugs; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /** * This class parses XML feeds from stackoverflow.com. Given an InputStream * representation of a feed, it returns a List of entries, where each list * element represents a single entry (post) in the XML feed. */ public class GoogleCodeXmlParser { private static final String ns = null; // We don't use namespaces public List<Entry> 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(); } } private List<Entry> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException { List<Entry> entries = new ArrayList<Entry>(); 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; } // This class represents a single entry (post) in the XML feed. // It includes the data members "title," "link," and "summary." 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, link); } 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, String prevLink) throws IOException, XmlPullParserException { String link = prevLink; 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")) { // if (relType.equals("replies")) { 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; } // Skips tags the parser isn't interested in. Uses depth to handle nested // tags. i.e., // if the next tag after a START_TAG isn't a matching END_TAG, it keeps // going until it // finds the matching END_TAG (as indicated by the value of "depth" being // 0). 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; } } } public static String buildHtmlEntityCode(String input) { StringBuffer output = new StringBuffer(input.length() * 2); int len = input.length(); int code,code1,code2,code3,code4; char ch; for( int i=0; i<len; ) { code1 = input.codePointAt(i); if( code1 >> 3 == 30 ){ code2 = input.codePointAt(i + 1); code3 = input.codePointAt(i + 2); code4 = input.codePointAt(i + 3); code = ((code1 & 7) << 18) | ((code2 & 63) << 12) | ((code3 & 63) << 6) | ( code4 & 63 ); i += 4; output.append("&#" + code + ";"); } else if( code1 >> 4 == 14 ){ code2 = input.codePointAt(i + 1); code3 = input.codePointAt(i + 2); code = ((code1 & 15) << 12) | ((code2 & 63) << 6) | ( code3 & 63 ); i += 3; output.append("&#" + code + ";"); } else if( code1 >> 5 == 6 ){ code2 = input.codePointAt(i + 1); code = ((code1 & 31) << 6) | ( code2 & 63 ); i += 2; output.append("&#" + code + ";"); } else { code = code1; i += 1; ch = (char)code; if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9') { output.append(ch); } else { output.append("&#" + code + ";"); } } } return output.toString(); } }