me.vertretungsplan.parser.IndiwareMobileParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parser Show documentation
Show all versions of parser Show documentation
Java library for parsing schools' substitution schedules. Supports multiple different systems mainly used in the German-speaking countries.
/*
* substitution-schedule-parser - Java library for parsing schools' substitution schedules
* Copyright (c) 2017 Johan v. Forstner
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package me.vertretungsplan.parser;
import me.vertretungsplan.exception.CredentialInvalidException;
import me.vertretungsplan.objects.Substitution;
import me.vertretungsplan.objects.SubstitutionSchedule;
import me.vertretungsplan.objects.SubstitutionScheduleData;
import me.vertretungsplan.objects.SubstitutionScheduleDay;
import org.apache.http.client.HttpResponseException;
import org.jetbrains.annotations.NotNull;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
/**
* Parser for the mobile version of substitution schedules created with the Indiware
* software.
*
* This parser can be accessed using "indiware-mobile"
for {@link SubstitutionScheduleData#setApi(String)}.
*
*
Configuration parameters
* These parameters can be supplied in {@link SubstitutionScheduleData#setData(JSONObject)} to configure the parser:
*
*
* baseurl
(Array of Strings, required)
* - Base URL of the Indiware mobile schedule.
*
*
*
* Additionally, this parser supports the parameters specified in {@link LoginHandler} for login-protected schedules.
*/
public class IndiwareMobileParser extends BaseParser {
private static final String PARAM_BASEURL = "baseurl";
private static final int MAX_DAYS = 7;
private JSONObject data;
public IndiwareMobileParser(SubstitutionScheduleData scheduleData, CookieProvider cookieProvider) {
super(scheduleData, cookieProvider);
data = scheduleData.getData();
}
@Override public SubstitutionSchedule getSubstitutionSchedule()
throws IOException, JSONException, CredentialInvalidException {
new LoginHandler(scheduleData, credential, cookieProvider).handleLogin(executor, cookieStore);
String baseurl = data.getString(PARAM_BASEURL) + "/";
List docs = new ArrayList<>();
HttpResponseException lastException = null;
for (int i = 0; i < MAX_DAYS; i++) {
LocalDate date = LocalDate.now().plusDays(i);
String dateStr = DateTimeFormat.forPattern("yyyyMMdd").print(date);
String filePrefix = scheduleData.getType() == SubstitutionSchedule.Type.TEACHER ? "PlanLe" : "PlanKl";
String url = baseurl + "mobdaten/" + filePrefix + dateStr + "" + ".xml?_=" + System.currentTimeMillis();
try {
String xml = httpGet(url, "UTF-8");
Document doc = Jsoup.parse(xml, url, Parser.xmlParser());
if (doc.select("kopf datei").text().equals(filePrefix + dateStr + ".xml")) {
docs.add(doc);
}
} catch (HttpResponseException e) {
lastException = e;
}
}
if (docs.size() == 0 && lastException != null) {
throw lastException;
}
SubstitutionSchedule v = SubstitutionSchedule.fromData(scheduleData);
for (Document doc:docs) {
v.addDay(parseDay(doc, colorProvider, scheduleData));
}
v.setClasses(getAllClasses());
v.setTeachers(getAllTeachers());
v.setWebsite(baseurl + "plankl.html");
return v;
}
static SubstitutionScheduleDay parseDay(Document doc, ColorProvider colorProvider, SubstitutionScheduleData scheduleData) {
SubstitutionScheduleDay day = new SubstitutionScheduleDay();
day.setDate(ParserUtils.parseDate(doc.select("Kopf > DatumPlan").text()));
day.setLastChange(ParserUtils.parseDateTime(doc.select("Kopf > Zeitstempel").text()));
for (Element klasse:doc.select("Klassen > Kl")) {
String className = klasse.select("Kurz").first().text();
HashSet classes = new HashSet<>();
classes.add(className);
for (Element lesson:klasse.select("Pl > Std")) {
if (lesson.select("If:not(:empty), Le[LeAe], Ra[RaAe], Fa[FaAe]").size() == 0) {
continue;
}
Substitution subst = new Substitution();
subst.setLesson(text(lesson.select("St")));
if (scheduleData.getType() == SubstitutionSchedule.Type.STUDENT) {
subst.setTeachers(split(text(lesson.select("Le"))));
subst.setClasses(classes);
} else {
subst.setClasses(split(text(lesson.select("Le"))));
subst.setTeachers(classes);
}
subst.setSubject(text(lesson.select("Fa")));
subst.setRoom(text(lesson.select("Ra")));
IndiwareParser.handleDescription(subst, text(lesson.select("If")), scheduleData.getType() == SubstitutionSchedule.Type.TEACHER);
if (subst.getType() == null) subst.setType("Vertretung");
subst.setColor(colorProvider.getColor(subst.getType()));
day.addSubstitution(subst);
}
}
for (Element info:doc.select("ZusatzInfo > ZiZeile")) {
day.getMessages().add(info.text());
}
return day;
}
@NotNull
private static HashSet split(String text) {
if (text != null) {
return new HashSet<>(Arrays.asList(text.split(",")));
} else {
return new HashSet<>();
}
}
private static String text(Elements elem) {
String text = elem.text().replace(" ", "").trim();
if (!text.isEmpty()) {
return text;
} else {
return null;
}
}
@Override public List getAllClasses() throws IOException, JSONException, CredentialInvalidException {
if (scheduleData.getType() == SubstitutionSchedule.Type.STUDENT) {
return parseClasses("PlanKl");
} else {
return new ArrayList<>();
}
}
@NotNull private List parseClasses(String filePrefix)
throws JSONException, IOException, CredentialInvalidException {
String baseurl = data.getString(PARAM_BASEURL) + "/";
HttpResponseException lastException = null;
for (int i = -4; i < MAX_DAYS; i++) {
LocalDate date = LocalDate.now().plusDays(i);
String dateStr = DateTimeFormat.forPattern("yyyyMMdd").print(date);
String url = baseurl + "mobdaten/" + filePrefix + dateStr + ".xml?_=" + System.currentTimeMillis();
try {
String xml = httpGet(url, "UTF-8");
Document doc = Jsoup.parse(xml, url, Parser.xmlParser());
List classes = new ArrayList<>();
for (Element klasse:doc.select("Klassen > Kl")) {
classes.add(klasse.select("Kurz").first().text());
}
return classes;
} catch (HttpResponseException e) {
lastException = e;
}
}
if (lastException != null) {
throw lastException;
} else {
return new ArrayList<>();
}
}
@Override public List getAllTeachers() throws IOException, JSONException, CredentialInvalidException {
if (scheduleData.getType() == SubstitutionSchedule.Type.TEACHER) {
return parseClasses("PlanLe");
} else {
return null;
}
}
}