mirror of
https://gitlab.com/oeffi/public-transport-enabler.git
synced 2025-07-19 08:49:58 +00:00
Migrate Kiel, Lübeck & Schleswig-Holstein to use XML station board for querying departures.
This commit is contained in:
parent
b031cfd2a8
commit
2ab38329c5
3 changed files with 12 additions and 176 deletions
|
@ -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);
|
||||
|
|
|
@ -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\\.:</span>\\n<span class=\"output\">([^<]*)<.*?" // location
|
||||
+ "Fahrplan:</span>\\n<span class=\"output\">\n" //
|
||||
+ "(\\d{2}\\.\\d{2}\\.\\d{2})[^\n]*,\n" // date
|
||||
+ "Abfahrt (\\d{1,2}:\\d{2}).*?" // time
|
||||
+ "<table class=\"resultTable\"[^>]*>(.+?)</table>" // 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("<tr class=\"(depboard-\\w*)\">(.*?)</tr>", Pattern.DOTALL);
|
||||
private static final Pattern P_DEPARTURES_FINE = Pattern.compile("\n" //
|
||||
+ "<td class=\"time\">(\\d{1,2}:\\d{2}).*?" // plannedTime
|
||||
+ "<img class=\"product\" src=\"/hafas-res/[^\"]*?(\\w+)_pic\\.png\"[^>]*>\\s*([^<]*)<.*?" // type,line
|
||||
+ "<a href=\"http://nah\\.sh\\.hafas\\.de/bin/stboard\\.exe/dn\\?input=(\\d+)&[^>]*>\n" // destinationId
|
||||
+ "([^\n]*)\n.*?" // destination
|
||||
+ "(?:<td class=\"center sepline top\">\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.<Departure> 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<Departure> departures = new ArrayList<Departure>(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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue