From 2ab38329c5fa90e21b9a887da59ae86682da05b0 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Sun, 1 Feb 2015 23:49:20 +0100 Subject: [PATCH] =?UTF-8?q?Migrate=20Kiel,=20L=C3=BCbeck=20&=20Schleswig-H?= =?UTF-8?q?olstein=20to=20use=20XML=20station=20board=20for=20querying=20d?= =?UTF-8?q?epartures.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schildbach/pte/AbstractHafasProvider.java | 4 +- enabler/src/de/schildbach/pte/ShProvider.java | 180 +----------------- .../pte/live/ShProviderLiveTest.java | 4 + 3 files changed, 12 insertions(+), 176 deletions(-) diff --git a/enabler/src/de/schildbach/pte/AbstractHafasProvider.java b/enabler/src/de/schildbach/pte/AbstractHafasProvider.java index 1d886b80..be55a76c 100644 --- a/enabler/src/de/schildbach/pte/AbstractHafasProvider.java +++ b/enabler/src/de/schildbach/pte/AbstractHafasProvider.java @@ -2302,7 +2302,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider if (location.hasLocation()) return nearbyLocationsByCoordinate(types, location.lat, location.lon, maxDistance, maxLocations); else if (location.type == LocationType.STATION && location.hasId()) - return nearbyStationsById(location.id); + return nearbyStationsById(location.id, maxDistance); else throw new IllegalArgumentException("cannot handle: " + location); } @@ -2330,7 +2330,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider } } - protected final NearbyLocationsResult nearbyStationsById(final String id) throws IOException + protected NearbyLocationsResult nearbyStationsById(final String id, final int maxDistance) throws IOException { final StringBuilder uri = new StringBuilder(stationBoardEndpoint); appendXmlNearbyStationsParameters(uri, id); diff --git a/enabler/src/de/schildbach/pte/ShProvider.java b/enabler/src/de/schildbach/pte/ShProvider.java index c555bfd0..bbe81f73 100644 --- a/enabler/src/de/schildbach/pte/ShProvider.java +++ b/enabler/src/de/schildbach/pte/ShProvider.java @@ -18,30 +18,15 @@ package de.schildbach.pte; import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.List; import java.util.regex.Matcher; -import java.util.regex.Pattern; import com.google.common.base.Charsets; -import de.schildbach.pte.dto.Departure; -import de.schildbach.pte.dto.Line; import de.schildbach.pte.dto.Location; import de.schildbach.pte.dto.LocationType; import de.schildbach.pte.dto.NearbyLocationsResult; -import de.schildbach.pte.dto.Position; import de.schildbach.pte.dto.Product; -import de.schildbach.pte.dto.QueryDeparturesResult; -import de.schildbach.pte.dto.QueryDeparturesResult.Status; -import de.schildbach.pte.dto.ResultHeader; -import de.schildbach.pte.dto.StationDepartures; -import de.schildbach.pte.util.ParserUtils; /** * @author Andreas Schildbach @@ -51,8 +36,6 @@ public class ShProvider extends AbstractHafasProvider public static final NetworkId NETWORK_ID = NetworkId.SH; private static final String API_BASE = "http://nah.sh.hafas.de/bin/"; - private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000; - public ShProvider() { super(API_BASE + "stboard.exe/dn", API_BASE + "ajax-getstop.exe/dn", API_BASE + "query.exe/dn", 10, Charsets.UTF_8); @@ -175,169 +158,18 @@ public class ShProvider extends AbstractHafasProvider final int maxLocations) throws IOException { if (location.type == LocationType.STATION && location.hasId()) - { - final StringBuilder uri = new StringBuilder(stationBoardEndpoint); - uri.append("?near=Anzeigen"); - uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50); - uri.append("&input=").append(normalizeStationId(location.id)); - - return htmlNearbyStations(uri.toString()); - } + return nearbyStationsById(location.id, maxDistance); else - { throw new IllegalArgumentException("cannot handle: " + location); - } } - private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern.compile(".*?" // - + "(?:" // - + "Bhf\\./Haltest\\.:\\n([^<]*)<.*?" // location - + "Fahrplan:\\n\n" // - + "(\\d{2}\\.\\d{2}\\.\\d{2})[^\n]*,\n" // date - + "Abfahrt (\\d{1,2}:\\d{2}).*?" // time - + "]*>(.+?)
" // content - + "|(verkehren an dieser Haltestelle keine)" // - + "|(Eingabe kann nicht interpretiert)" // - + "|(Verbindung zum Server konnte leider nicht hergestellt werden|kann vom Server derzeit leider nicht bearbeitet werden))" // - + ".*?" // - , Pattern.DOTALL); - private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("(.*?)", Pattern.DOTALL); - private static final Pattern P_DEPARTURES_FINE = Pattern.compile("\n" // - + "(\\d{1,2}:\\d{2}).*?" // plannedTime - + "]*>\\s*([^<]*)<.*?" // type,line - + "]*>\n" // destinationId - + "([^\n]*)\n.*?" // destination - + "(?:\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position - , Pattern.DOTALL); - @Override - public QueryDeparturesResult queryDepartures(final String stationId, final Date time, final int maxDepartures, final boolean equivs) - throws IOException + protected NearbyLocationsResult nearbyStationsById(final String id, final int maxDistance) throws IOException { - final ResultHeader header = new ResultHeader(SERVER_PRODUCT); - final QueryDeparturesResult result = new QueryDeparturesResult(header); - - // scrape page final StringBuilder uri = new StringBuilder(stationBoardEndpoint); - appendXmlStationBoardParameters(uri, time, stationId, maxDepartures, false, null); - final CharSequence page = ParserUtils.scrape(uri.toString()); - - // System.out.println(uri); - // System.out.println(page); - - // parse page - final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page); - if (mHeadCoarse.matches()) - { - // messages - if (mHeadCoarse.group(5) != null) - { - result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId), - Collections. emptyList(), null)); - return result; - } - else if (mHeadCoarse.group(6) != null) - return new QueryDeparturesResult(header, Status.INVALID_STATION); - else if (mHeadCoarse.group(7) != null) - return new QueryDeparturesResult(header, Status.SERVICE_DOWN); - - final String[] placeAndName = splitStationName(ParserUtils.resolveEntities(mHeadCoarse.group(1))); - final Calendar currentTime = new GregorianCalendar(timeZone); - currentTime.clear(); - ParserUtils.parseGermanDate(currentTime, mHeadCoarse.group(2)); - ParserUtils.parseEuropeanTime(currentTime, mHeadCoarse.group(3)); - - final List departures = new ArrayList(8); - String oldZebra = null; - - final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(4)); - while (mDepCoarse.find()) - { - final String zebra = mDepCoarse.group(1); - if (oldZebra != null && zebra.equals(oldZebra)) - throw new IllegalArgumentException("missed row? last:" + zebra); - else - oldZebra = zebra; - - final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2)); - if (mDepFine.matches()) - { - final Calendar plannedTime = new GregorianCalendar(timeZone); - plannedTime.setTimeInMillis(currentTime.getTimeInMillis()); - ParserUtils.parseEuropeanTime(plannedTime, mDepFine.group(1)); - - if (plannedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS) - plannedTime.add(Calendar.DAY_OF_MONTH, 1); - - final String lineType = mDepFine.group(2); - final char product = intToProduct(Integer.parseInt(lineType)); - final String lineStr = Character.toString(product) + normalizeLineName(mDepFine.group(3).trim()); - final Line line = new Line(null, lineStr, lineStyle(null, lineStr)); - - final String destinationId = mDepFine.group(4); - final String destinationName = ParserUtils.resolveEntities(mDepFine.group(5)); - final Location destination; - if (destinationId != null) - { - final String[] destinationPlaceAndName = splitStationName(destinationName); - destination = new Location(LocationType.STATION, destinationId, destinationPlaceAndName[0], destinationPlaceAndName[1]); - } - else - { - destination = new Location(LocationType.ANY, null, null, destinationName); - } - - final Position position = parsePosition(ParserUtils.resolveEntities(mDepFine.group(6))); - - final Departure dep = new Departure(plannedTime.getTime(), null, line, position, destination, null, null); - - if (!departures.contains(dep)) - departures.add(dep); - } - else - { - throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(2) + "' on " + stationId); - } - } - - result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId, placeAndName[0], placeAndName[1]), - departures, null)); - return result; - } - else - { - throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId); - } - } - - @Override - protected char normalizeType(final String type) - { - final String ucType = type.toUpperCase(); - - if ("IXB".equals(ucType)) // ICE - return 'I'; - if ("ECW".equals(ucType)) // EC - return 'I'; - if ("DPF".equals(ucType)) // Hamburg-Koeln-Express - return 'I'; - if ("RRT".equals(ucType)) // TGV - return 'I'; - - if ("ZRB".equals(ucType)) // Zahnradbahn - return 'R'; - - if ("KBS".equals(ucType)) - return 'B'; - if ("KB1".equals(ucType)) - return 'B'; - if ("KLB".equals(ucType)) - return 'B'; - - final char t = super.normalizeType(type); - if (t != 0) - return t; - - return 0; + uri.append("?near=Anzeigen"); + uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50); + uri.append("&input=").append(normalizeStationId(id)); + return htmlNearbyStations(uri.toString()); } } diff --git a/enabler/test/de/schildbach/pte/live/ShProviderLiveTest.java b/enabler/test/de/schildbach/pte/live/ShProviderLiveTest.java index 11e09a7d..53beed3e 100644 --- a/enabler/test/de/schildbach/pte/live/ShProviderLiveTest.java +++ b/enabler/test/de/schildbach/pte/live/ShProviderLiveTest.java @@ -92,6 +92,10 @@ public class ShProviderLiveTest extends AbstractProviderLiveTest final QueryTripsResult result = queryTrips(new Location(LocationType.STATION, "8002547", null, "Flughafen Hamburg"), null, new Location( LocationType.STATION, "8003781", null, "Lübeck Airport"), new Date(), true, Product.ALL, WalkSpeed.NORMAL, Accessibility.NEUTRAL); print(result); + + if (!result.context.canQueryLater()) + return; + final QueryTripsResult laterResult = queryMoreTrips(result.context, true); print(laterResult); }