package de.boge.infosphere.parser;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.text.Html;
/**
* Der Parser l�dt die gew�nschten Daten aus dem RSS-Feed der Website und formatiert sie, sodass die Daten in den entpsprechenden Activitys angezeigt werden k�nnen.
*/
public class Parser {
private final String[] FEEDS = new String[]{"http://schuelerlabor.informatik.rwth-aachen.de/rss.xml",
"http://schuelerlabor.informatik.rwth-aachen.de/feeds/termine?xml", "http://schuelerlabor.informatik.rwth-aachen.de/module_rss"};
private final Context context;
private final int chosenFeed;
private ArrayList<Object> feedObjects = new ArrayList<Object>();
public Parser(Context context, int feed) {
this.context = context;
this.chosenFeed = feed;
}
/**
* Gibt die Feed-Objekte als Liste zur�ck.
* Gegebenenfalls wird vorher der Feed geparst oder die Daten werden aus dem tempor�ren Cache genommen.
*
* @param max Maximale Anzahl an Eintr�gen, die zur�ckgegeben werden sollen. Standard: 0 --> Alle
* @return Liste mit allen (gew�hlten) Feed-Objekten
*/
public ArrayList<Object> getFeedObjects(int max) {
parseFeed();
if (max == 0) return feedObjects;
if (feedObjects.size() < max) max = feedObjects.size();
// Erstellt eine temp�r�re Liste mit der gew�hlten maximalen Anzahl an Eintr�gen
ArrayList<Object> chosenFeedObjects = new ArrayList<Object>();
for (int i = 0; i < max; i++) {
chosenFeedObjects.add(feedObjects.get(i));
}
return chosenFeedObjects;
}
/**
* Parst den Feed und tr�gt den Inhalt jeweils als Objekt in die Liste ein.
*/
private void parseFeed() {
// Falls keine Internetverbindung besteht, abbrechen;
// (leere Liste wird zur�ckgegeben; wird von der Activity entsprechend behandelt)
if (!isOnline()) {
return;
}
// Initiere den XML-Parser
XmlPullParserFactory pullParserFactory;
try {
pullParserFactory = XmlPullParserFactory.newInstance();
XmlPullParser parser = pullParserFactory.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(new URL(FEEDS[chosenFeed]).openStream(), null);
// Parse den gew�hlten Feed (siehe Konstruktor)
if (chosenFeed == 0) {
parseNewsXML(parser);
} else if (chosenFeed == 1) {
parseCalendarXML(parser);
} else if (chosenFeed == 2) {
parseModulXML(parser);
}
} catch (XmlPullParserException ignored) {} catch (IOException ignored) {}
}
/**
* Parst den News-Feed und speichert die News als NewsItem in der parsedObjects-Liste
* @param parser Welcher Parser die Aufgabe �bernehmen soll.
*/
private void parseNewsXML(XmlPullParser parser) throws XmlPullParserException, IOException {
int eventType = parser.getEventType();
String name;
NewsItem currentItem = null;
// Solange nicht das Ende des Feeds erreicht ist, wird dieser durchlaufen
while (eventType != XmlPullParser.END_DOCUMENT) {
name = "";
if (eventType == XmlPullParser.START_TAG) {
name = parser.getName();
if (name.equalsIgnoreCase("item")) {
// Anfang einer News --> Erzeuge neues NewsItem
currentItem = new NewsItem();
} else if (name.equalsIgnoreCase("title") && currentItem != null) {
// Titel der News
currentItem.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase("description") && currentItem != null) {
// Inhalt der News
String tempDesc = parser.nextText();
// Nur den ersten Teil (Beschreibung) des Tags speichern
tempDesc = tempDesc.split("<div class=\"field ")[0];
// Bilder sollen (falls vorhanden) angezeigt werden
tempDesc = tempDesc.replace("/sites/default/files/content/Bilder/", "http://schuelerlabor.informatik.rwth-aachen.de/sites/default/files/content/Bilder/");
currentItem.setContent(tempDesc);
} else if (name.equalsIgnoreCase("pubDate") && currentItem != null) {
// Ver�ffentlichungszeitpunkt der News
String tempDate = parser.nextText();
// Entferne den Wochentag und schreibe den Monat aus
tempDate = tempDate.replace("+0000", "");
tempDate = tempDate.replace("Mon, ", "");
tempDate = tempDate.replace("Tue, ", "");
tempDate = tempDate.replace("Wed, ", "");
tempDate = tempDate.replace("Thu, ", "");
tempDate = tempDate.replace("Fri, ", "");
tempDate = tempDate.replace("Sat, ", "");
tempDate = tempDate.replace("Sun, ", "");
tempDate = tempDate.replace(" Jan", ". Januar");
tempDate = tempDate.replace(" Feb", ". Februar");
tempDate = tempDate.replace(" Mar", ". M�rz");
tempDate = tempDate.replace(" Apr", ". April");
tempDate = tempDate.replace(" May", ". Mai");
tempDate = tempDate.replace(" Jun", ". Juni");
tempDate = tempDate.replace(" Jul", ". Juli");
tempDate = tempDate.replace(" Aug", ". August");
tempDate = tempDate.replace(" Sep", ". September");
tempDate = tempDate.replace(" Oct", ". Oktober");
tempDate = tempDate.replace(" Nov", ". November");
tempDate = tempDate.replace(" Dec", ". Dezember");
tempDate = tempDate.trim();
currentItem.setDate(tempDate);
}
} else if (eventType == XmlPullParser.END_TAG) {
// Ende des News-Items --> Speichere das Objekt in der Liste und entferne das aktuelle Objekt
name = parser.getName();
if (name.equalsIgnoreCase("item") && currentItem != null) {
feedObjects.add(currentItem);
currentItem = null;
}
}
eventType = parser.next();
}
}
/**
* Parst den Kalender-Feed und speichert die Termine als CalendarItem in der parsedObjects-Liste
* @param parser Welcher Parser die Aufgabe �bernehmen soll.
*/
private void parseCalendarXML(XmlPullParser parser) throws XmlPullParserException, IOException {
int eventType = parser.getEventType();
String name;
CalendarItem currentItem = null;
// Solange nicht das Ende des Feeds erreicht ist, wird dieser durchlaufen
while (eventType != XmlPullParser.END_DOCUMENT) {
name = "";
if (eventType == XmlPullParser.START_TAG) {
name = parser.getName();
if (name.equalsIgnoreCase("item")) {
// Anfang eines Termins --> Erzeuge neues CalendarItem
currentItem = new CalendarItem();
} else if (name.equalsIgnoreCase("title") && currentItem != null) {
// Titel des Termins
currentItem.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase("link") && currentItem != null) {
// Link mit weiteren Infos
currentItem.setMore(parser.nextText());
} else if (name.equalsIgnoreCase("description") && currentItem != null) {
// Beschreibung des Termins (Datum, ...)
String tempDesc = parser.nextText();
// HTML-Tags entfernen
tempDesc = tempDesc.replace("<", "<");
tempDesc = tempDesc.replace(">", ">");
tempDesc = tempDesc.replace(""", "\"");
// Anfangs und Endzeitpunkt auslesen (RegEx)
Pattern p = Pattern.compile("<span class=\"date-display-single\">(.*?)</span>");
Pattern p2 = Pattern.compile("<span class=\"date-display-start\">(.*?)</span>");
Pattern p3 = Pattern.compile("<span class=\"date-display-end\">(.*?)</span>");
Matcher m = p.matcher(tempDesc);
Matcher m2 = p2.matcher(tempDesc);
Matcher m3 = p3.matcher(tempDesc);
if (m.find()) {
currentItem.setStartDate(m.group(1));
currentItem.setEndDate(m.group(1));
} else if (m2.find() && m3.find()){
currentItem.setStartDate(m2.group(1));
currentItem.setEndDate(m3.group(1));
} else {
currentItem.setStartDate("Termin unbekannt");
currentItem.setEndDate("Termin unbekannt");
}
currentItem.setDescription(tempDesc);
}
} else if (eventType == XmlPullParser.END_TAG) {
// Ende des Termins --> Speichere das Objekt in der Liste und entferne das aktuelle Objekt
name = parser.getName();
if (name.equalsIgnoreCase("item") && currentItem != null) {
feedObjects.add(currentItem);
currentItem = null;
}
}
eventType = parser.next();
}
Collections.reverse(feedObjects);
}
/**
* Parst den Modul-Feed und speichert die Module als ModulItem in der parsedObjects-Liste
* @param parser Welcher Parser die Aufgabe �bernehmen soll.
*/
private void parseModulXML(XmlPullParser parser) throws XmlPullParserException, IOException {
int eventType = parser.getEventType();
String name;
ModulItem currentItem = null;
// Solange nicht das Ende des Feeds erreicht ist, wird dieser durchlaufen
while (eventType != XmlPullParser.END_DOCUMENT) {
name = "";
if (eventType == XmlPullParser.START_TAG) {
name = parser.getName();
if (name.equalsIgnoreCase("item")) {
// Anfang eines Moduls --> Erzeuge neues ModulItem
currentItem = new ModulItem();
} else if (name.equalsIgnoreCase("title") && currentItem != null) {
// Titel des Moduls
currentItem.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase("description") && currentItem != null) {
// Beschreibung des Moduls
String tempDesc = parser.nextText();
// HTML-Tags entfernen
tempDesc = tempDesc.replace("<", "<");
tempDesc = tempDesc.replace(">", ">");
tempDesc = tempDesc.replace(""", "\"");
// Beschreibung des Moduls: Erster Teil des Feeds, entferne vorher HTML-Tags / -Elemente
String newDesc = Html.fromHtml(tempDesc.split("<div class=\"field ")[0]).toString();
// Beschreibung k�rzen, damit der Nutzer nicht "erschlagen" wird
if (newDesc.length() > 200) {
newDesc = newDesc.substring(0, 200) + "...";
}
currentItem.setDescription(newDesc);
// Ganze Description in Zeilen zerlegen
String[] lines = tempDesc.split("\\r?\\n");
// Nach Zeilen f�r Vorwissen und Dauer suchen, diese dann von HTML-Tags befreien
// und im Eintrag speichern
for (int i = 0; i < lines.length; i++) {
if (lines[i].trim().startsWith("<div class=\"field field-type-text field-field-modul-vorwissen\">")) {
currentItem.setKnowledge(Html.fromHtml(lines[i+4]).toString().replace("ä", "�").replace("ö", "�").replace("ü", "�"));
} else if (lines[i].trim().startsWith("<div class=\"field field-type-number-float field-field-modul-dauer\">")) {
currentItem.setDuration(Html.fromHtml(lines[i+5]).toString().replace("Zeitstunden", " Zeitstunden"));
}
}
// Zielgruppe heraussuchen (aktuell nur _eine_ m�glich!)
Pattern p = Pattern.compile("<a href=\"/category/jahrgangsstufe/(.*?)\" rel=\"tag\" ");
Matcher m = p.matcher(tempDesc);
if (m.find()) {
currentItem.setCategory(m.group(1));
}
}
} else if (eventType == XmlPullParser.END_TAG) {
// Ende des Moduls --> Speichere das Objekt in der Liste und entferne das aktuelle Objekt
name = parser.getName();
if (name.equalsIgnoreCase("item") && currentItem != null) {
feedObjects.add(currentItem);
currentItem = null;
}
}
eventType = parser.next();
}
}
/**
* Pr�ft, ob eine Internetverbindung besteht.
* @return Ob das Smartphone eine aktive Internetverbindung hat
*/
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
}