/*
* 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();
}
}