All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.vertretungsplan.parser.CSVParser Maven / Gradle / Ivy

Go to download

Java library for parsing schools' substitution schedules. Supports multiple different systems mainly used in the German-speaking countries.

There is a newer version: 1.0.0-beta356
Show newest version
/*
 * substitution-schedule-parser - Java library for parsing schools' substitution schedules
 * Copyright (c) 2016 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.fluent.Request;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

/**
 * Generic parser for substitution schedules in CSV format.
 * 

* This parser can be accessed using "csv" for {@link SubstitutionScheduleData#setApi(String)}. * *

Configuration parameters

* These parameters can be supplied in {@link SubstitutionScheduleData#setData(JSONObject)} to configure the parser: * *
*
url (String, required)
*
The url of the CSV file to be fetched
* *
separator (String, required)
*
The separator used in the CSV file (such as ",", ";" or "\t")
* *
columns (Array of Strings, required)
*
The order of columns used in the CSV file. Entries can be: "lesson", "subject", * "previousSubject", "type", "type-entfall", "room", "previousRoom", "teacher", "previousTeacher", desc", * "desc-type", "class", "day", "stand", "ignore"
* *
classes (Array of Strings, required if classesUrl not specified)
*
The list of all classes, as they can appear in the schedule
* *
website (String, recommended)
*
The URL of a website where the substitution schedule can be seen online
* *
skipLines (Integer, optional)
*
The number of lines to skip at the beginning of the CSV file. Default: 0
* *
classesUrl (String, optional)
*
The URL of an additional CSV file containing the classes, one per line
* *
classRegex (String, optional)
*
RegEx to modify the classes set on the schedule (in {@link #getSubstitutionSchedule()}, not * {@link #getAllClasses()}. The RegEx is matched against the class using {@link Matcher#find()}. If the RegEx * contains a group, the content of the first group {@link Matcher#group(int)} is used as the resulting class. * Otherwise, {@link Matcher#group()} is used. If the RegEx cannot be matched ({@link Matcher#find()} returns * false), the class is set to an empty string. *
*
* * Additionally, this parser supports the parameters specified in {@link LoginHandler} for login-protected schedules. */ public class CSVParser extends BaseParser { private static final String PARAM_SEPARATOR = "separator"; private static final String PARAM_SKIP_LINES = "skipLines"; private static final String PARAM_COLUMNS = "columns"; private static final String PARAM_WEBSITE = "website"; private static final String PARAM_CLASSES_URL = "classesUrl"; private static final String PARAM_CLASSES = "classes"; private static final String PARAM_URL = "url"; private JSONObject data; public CSVParser(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 url = data.getString(PARAM_URL); String response = executor.execute(Request.Get(url)).returnContent().asString(); return parseCSV(response); } @NotNull SubstitutionSchedule parseCSV(String response) throws JSONException, IOException { SubstitutionSchedule schedule = SubstitutionSchedule.fromData(scheduleData); String[] lines = response.split("\n"); String separator = data.getString(PARAM_SEPARATOR); for (int i = data.optInt(PARAM_SKIP_LINES, 0); i < lines.length; i++) { String[] columns = lines[i].split(separator); Substitution v = new Substitution(); String dayName = null; String stand = ""; int j = 0; for (String column:columns) { String type = data.getJSONArray(PARAM_COLUMNS) .getString(j); switch (type) { case "lesson": v.setLesson(column); break; case "subject": v.setSubject(column); break; case "previousSubject": v.setPreviousSubject(column); break; case "type": v.setType(column); v.setColor(colorProvider.getColor(column)); break; case "type-entfall": if (column.equals("x")) { v.setType("Entfall"); v.setColor(colorProvider.getColor("Entfall")); } else { v.setType("Vertretung"); v.setColor(colorProvider.getColor("Vertretung")); } break; case "room": v.setRoom(column); break; case "teacher": v.setTeacher(column); break; case "previousTeacher": v.setPreviousTeacher(column); break; case "desc": v.setDesc(column); break; case "desc-type": v.setDesc(column); String recognizedType = recognizeType(column); v.setType(recognizedType); v.setColor(colorProvider.getColor(recognizedType)); break; case "previousRoom": v.setPreviousRoom(column); break; case "class": v.getClasses().add(getClassName(column, data)); break; case "day": dayName = column; break; case "stand": stand = column; break; case "ignore": break; default: throw new IllegalArgumentException("Unknown column type: " + column); } j++; } if (v.getType() == null) { v.setType("Vertretung"); v.setColor(colorProvider.getColor("Vertretung")); } if (dayName != null) { SubstitutionScheduleDay day = new SubstitutionScheduleDay(); day.setDateString(dayName); day.setDate(ParserUtils.parseDate(dayName)); day.setLastChangeString(stand); day.setLastChange(ParserUtils.parseDateTime(stand)); day.addSubstitution(v); schedule.addDay(day); } } if (scheduleData.getData().has(PARAM_WEBSITE)) { schedule.setWebsite(scheduleData.getData().getString(PARAM_WEBSITE)); } schedule.setClasses(getAllClasses()); schedule.setTeachers(getAllTeachers()); return schedule; } @Override public List getAllClasses() throws IOException, JSONException { if (data.has(PARAM_CLASSES_URL)) { String url = data.getString(PARAM_CLASSES_URL); String response = executor.execute(Request.Get(url)).returnContent().asString(); List classes = new ArrayList<>(); for (String string:response.split("\n")) { classes.add(string.trim()); } return classes; } else { JSONArray classesJson = data.getJSONArray(PARAM_CLASSES); List classes = new ArrayList<>(); for (int i = 0; i < classesJson.length(); i++) { classes.add(classesJson.getString(i)); } return classes; } } @Override public List getAllTeachers() { return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy