Java tutorial
/* Vertretungsplan - Android-App fr Vertretungsplne von Schulen Copyright (C) 2014 Johan v. Forstner This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see [http://www.gnu.org/licenses/]. */ package com.johan.vertretungsplan.parser; import com.johan.vertretungsplan.objects.KlassenVertretungsplan; import com.johan.vertretungsplan.objects.Schule; import com.johan.vertretungsplan.objects.Vertretung; import com.johan.vertretungsplan.objects.VertretungsplanTag; import org.json.JSONException; import org.json.JSONObject; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.nodes.TextNode; import org.jsoup.select.Elements; import java.io.IOException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Enthlt gemeinsam genutzte Funktionen fr die Parser fr * Untis-Vertretungsplne * */ public abstract class UntisCommonParser extends BaseParser { private static final String[] EXCLUDED_CLASS_NAMES = new String[] { "-----" }; public UntisCommonParser(Schule schule) { super(schule); } /** * Parst eine Vertretungstabelle eines Untis-Vertretungsplans * * @param table * das <code>table</code>-Element des HTML-Dokuments, das geparst * werden soll * @param data * Daten von der Schule (aus <code>Schule.getData()</code>) * @param tag * der {@link VertretungsplanTag} in dem die Vertretungen * gespeichert werden sollen * @throws JSONException */ protected void parseVertretungsplanTable(Element table, JSONObject data, VertretungsplanTag tag) throws JSONException { if (data.optBoolean("class_in_extra_line")) { for (Element element : table.select("td.inline_header")) { String className = getClassName(element.text(), data); if (isValidClass(className)) { KlassenVertretungsplan kv = new KlassenVertretungsplan(className); Element zeile = null; try { zeile = element.parent().nextElementSibling(); if (zeile.select("td") == null) { zeile = zeile.nextElementSibling(); } while (zeile != null && !zeile.select("td").attr("class").equals("list inline_header")) { Vertretung v = new Vertretung(); int i = 0; for (Element spalte : zeile.select("td")) { if (!hasData(spalte.text())) { i++; continue; } String type = data.getJSONArray("columns").getString(i); if (type.equals("lesson")) v.setLesson(spalte.text()); else if (type.equals("subject")) v.setSubject(spalte.text()); else if (type.equals("previousSubject")) v.setPreviousSubject(spalte.text()); else if (type.equals("type")) v.setType(spalte.text()); else if (type.equals("type-entfall")) { if (spalte.text().equals("x")) v.setType("Entfall"); else v.setType("Vertretung"); } else if (type.equals("room")) v.setRoom(spalte.text()); else if (type.equals("teacher")) v.setTeacher(spalte.text()); else if (type.equals("previousTeacher")) v.setPreviousTeacher(spalte.text()); else if (type.equals("desc")) v.setDesc(spalte.text()); else if (type.equals("desc-type")) { v.setDesc(spalte.text()); v.setType(recognizeType(spalte.text())); } else if (type.equals("previousRoom")) v.setPreviousRoom(spalte.text()); i++; } if (v.getDesc() != null && v.getLesson() == null && v.getPreviousRoom() == null && v.getPreviousSubject() == null && v.getPreviousTeacher() == null && v.getRoom() == null && v.getSubject() == null && v.getTeacher() == null && v.getType() == null) { // Beschreibung aus der letzten Zeile fortgesetzt Vertretung previousVertretung = kv.getVertretung() .get(kv.getVertretung().size() - 1); previousVertretung.setDesc(previousVertretung.getDesc() + " " + v.getDesc()); zeile = zeile.nextElementSibling(); continue; } if (v.getType() == null) v.setType("Vertretung"); if (!v.getLesson().equals("")) { kv.add(v); } zeile = zeile.nextElementSibling(); } tag.getKlassen().put(className, kv); } catch (Throwable e) { e.printStackTrace(); } } } } else { boolean hasType = false; for (int i = 0; i < data.getJSONArray("columns").length(); i++) { if (data.getJSONArray("columns").getString(i).equals("type")) hasType = true; } Vertretung previousVertretung = null; for (Element zeile : table.select("tr.list.odd:not(:has(td.inline_header)), " + "tr.list.even:not(:has(td.inline_header)), " + "tr:has(td[align=center]:has(font[color]))")) { Vertretung v = new Vertretung(); String klassen = ""; int i = 0; for (Element spalte : zeile.select("td")) { if (!hasData(spalte.text())) { i++; continue; } String type = data.getJSONArray("columns").getString(i); if (type.equals("lesson")) v.setLesson(spalte.text()); else if (type.equals("subject")) v.setSubject(spalte.text()); else if (type.equals("previousSubject")) v.setPreviousSubject(spalte.text()); else if (type.equals("type")) v.setType(spalte.text()); else if (type.equals("type-entfall")) { if (spalte.text().equals("x")) v.setType("Entfall"); else if (!hasType) v.setType("Vertretung"); } else if (type.equals("room")) v.setRoom(spalte.text()); else if (type.equals("previousRoom")) v.setPreviousRoom(spalte.text()); else if (type.equals("desc")) v.setDesc(spalte.text()); else if (type.equals("desc-type")) { v.setDesc(spalte.text()); v.setType(recognizeType(spalte.text())); } else if (type.equals("teacher")) v.setTeacher(spalte.text()); else if (type.equals("previousTeacher")) v.setPreviousTeacher(spalte.text()); else if (type.equals("class")) klassen = getClassName(spalte.text(), data); i++; } if (v.getDesc() != null && v.getLesson() == null && v.getPreviousRoom() == null && v.getPreviousSubject() == null && v.getPreviousTeacher() == null && v.getRoom() == null && v.getSubject() == null && v.getTeacher() == null && v.getType() == null && previousVertretung != null) { // Beschreibung aus der letzten Zeile fortgesetzt previousVertretung.setDesc(previousVertretung.getDesc() + " " + v.getDesc()); continue; } if (v.getType() == null) { if (zeile.select("strike").size() > 0 || (v.getSubject() == null && v.getRoom() == null && v.getTeacher() == null && v.getPreviousSubject() != null)) v.setType("Entfall"); else v.setType("Vertretung"); } List<String> affectedClasses; // Detect things like "5-12" Pattern pattern = Pattern.compile("(\\d+) ?- ?(\\d+)"); Matcher matcher = pattern.matcher(klassen); if (matcher.find()) { affectedClasses = new ArrayList<String>(); int min = Integer.parseInt(matcher.group(1)); int max = Integer.parseInt(matcher.group(2)); try { for (String klasse : getAllClasses()) { Pattern pattern2 = Pattern.compile("\\d+"); Matcher matcher2 = pattern2.matcher(klasse); if (matcher2.find()) { int num = Integer.parseInt(matcher2.group()); if (min <= num && num <= max) affectedClasses.add(klasse); } } } catch (IOException e) { e.printStackTrace(); } } else { if (data.optBoolean("classes_separated", true)) { affectedClasses = Arrays.asList(klassen.split(", ")); } else { affectedClasses = new ArrayList<String>(); try { for (String klasse : getAllClasses()) { // TODO: // Gibt es // eine // bessere // Mglichkeit? StringBuilder regex = new StringBuilder(); for (char character : klasse.toCharArray()) { regex.append(character); regex.append(".*"); } if (klassen.matches(regex.toString())) affectedClasses.add(klasse); } } catch (IOException e) { e.printStackTrace(); } } } for (String klasse : affectedClasses) { if (isValidClass(klasse)) { KlassenVertretungsplan kv = tag.getKlassen().get(klasse); if (kv == null) kv = new KlassenVertretungsplan(klasse); kv.add(v); tag.getKlassen().put(klasse, kv); } } previousVertretung = v; } } if (data.optBoolean("sort_classes")) { List<KlassenVertretungsplan> list = new ArrayList<>(tag.getKlassen().values()); Collections.sort(list, new Comparator<KlassenVertretungsplan>() { @Override public int compare(KlassenVertretungsplan o1, KlassenVertretungsplan o2) { return o1.getKlasse().compareTo(o2.getKlasse()); } }); LinkedHashMap<String, KlassenVertretungsplan> hashMap = new LinkedHashMap<>(); for (KlassenVertretungsplan klasse : list) { hashMap.put(klasse.getKlasse(), klasse); } tag.setKlassen(hashMap); } } private boolean hasData(String text) { return !text.trim().equals("") && !text.trim().equals("---"); } /** * Parst eine "Nachrichten zum Tag"-Tabelle aus Untis-Vertretungsplnen * * @param table * das <code>table</code>-Element des HTML-Dokuments, das geparst * werden soll * @param data * Daten von der Schule (aus <code>Schule.getData()</code>) * @param tag * der {@link VertretungsplanTag} in dem die Nachrichten * gespeichert werden sollen */ protected void parseNachrichten(Element table, JSONObject data, VertretungsplanTag tag) { Elements zeilen = table.select("tr:not(:contains(Nachrichten zum Tag))"); for (Element i : zeilen) { Elements spalten = i.select("td"); String info = ""; for (Element b : spalten) { info += "\n" + TextNode.createFromEncoded(b.html(), null).getWholeText(); } info = info.substring(1); // remove first \n tag.getNachrichten().add(info); } } protected VertretungsplanTag parseMonitorVertretungsplanTag(Document doc, JSONObject data) throws JSONException { VertretungsplanTag tag = new VertretungsplanTag(); tag.setDatum(doc.select(".mon_title").first().text().replaceAll(" \\(Seite \\d+ / \\d+\\)", "")); if (doc.select("table.mon_head td[align=right] p").size() == 0 || schule.getData().optBoolean("stand_links", false)) { tag.setStand(doc.select("body").html().substring(0, doc.select("body").html().indexOf("<p>") - 1)); } else { Element stand = doc.select("table.mon_head td[align=right] p").first(); String info = stand.text(); tag.setStand(info.substring(info.indexOf("Stand:"))); } // NACHRICHTEN if (doc.select("table.info").size() > 0) parseNachrichten(doc.select("table.info").first(), data, tag); // VERTRETUNGSPLAN if (doc.select("table:has(tr.list)").size() > 0) parseVertretungsplanTable(doc.select("table:has(tr.list)").first(), data, tag); return tag; } private boolean isValidClass(String klasse) { if (klasse == null) return false; if (Arrays.asList(EXCLUDED_CLASS_NAMES).contains(klasse)) { return false; } else if (schule.getData().has("exclude_classes") && contains(schule.getData().getJSONArray("exclude_classes"), klasse)) { return false; } return true; } }