rudimentary connnections using API for Belgium and Switzerland

git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@302 0924bc21-9374-b0fa-ee44-9ff1593b38f0
This commit is contained in:
andreas.schildbach 2010-10-17 14:17:11 +00:00
parent b990d82f8e
commit b9f572b658
10 changed files with 515 additions and 69 deletions

View file

@ -20,7 +20,11 @@ package de.schildbach.pte;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -31,9 +35,12 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import de.schildbach.pte.dto.Connection;
import de.schildbach.pte.dto.GetConnectionDetailsResult;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.Station;
import de.schildbach.pte.util.Color;
import de.schildbach.pte.util.ParserUtils;
@ -46,29 +53,62 @@ public abstract class AbstractHafasProvider implements NetworkProvider
{
private static final String DEFAULT_ENCODING = "ISO-8859-1";
private final String autocompleteUri;
private final String prod;
private final String apiUri;
private static final String prod = "hafas";
private final String accessId;
public AbstractHafasProvider(final String autocompleteUri, final String prod, final String accessId)
public AbstractHafasProvider(final String apiUri, final String accessId)
{
this.autocompleteUri = autocompleteUri;
this.prod = prod;
this.apiUri = apiUri;
this.accessId = accessId;
}
private final String wrap(final String request)
{
return "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>" //
+ "<ReqC ver=\"1.1\" prod=\"" + prod + "\" lang=\"DE\"" + (accessId != null ? " accessId=\"" + accessId + "\"" : "") + ">" //
+ request //
+ "</ReqC>";
}
private static final Location parseLocation(final XmlPullParser pp)
{
final String type = pp.getName();
if ("Station".equals(type))
{
final String name = pp.getAttributeValue(null, "name").trim();
final int id = Integer.parseInt(pp.getAttributeValue(null, "externalStationNr"));
final int x = Integer.parseInt(pp.getAttributeValue(null, "x"));
final int y = Integer.parseInt(pp.getAttributeValue(null, "y"));
return new Location(LocationType.STATION, id, y, x, name);
}
throw new IllegalStateException("cannot handle: " + type);
}
private static final Location parsePoi(final XmlPullParser pp)
{
final String type = pp.getName();
if ("Poi".equals(type))
{
String name = pp.getAttributeValue(null, "name").trim();
if (name.equals("unknown"))
name = null;
final int x = Integer.parseInt(pp.getAttributeValue(null, "x"));
final int y = Integer.parseInt(pp.getAttributeValue(null, "y"));
return new Location(LocationType.POI, 0, y, x, name);
}
throw new IllegalStateException("cannot handle: " + type);
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String request = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>" //
+ "<ReqC ver=\"1.1\" prod=\"" + prod + "\" lang=\"DE\"" + (accessId != null ? " accessId=\"" + accessId + "\"" : "") + ">" //
+ "<LocValReq id=\"station\" maxNr=\"10\"><ReqLoc match=\"" + constraint + "\" type=\"ST\"/></LocValReq>" //
+ "<LocValReq id=\"poi\" maxNr=\"10\"><ReqLoc match=\"" + constraint + "\" type=\"POI\"/></LocValReq>" //
+ "</ReqC>";
final String request = "<LocValReq id=\"station\" maxNr=\"10\"><ReqLoc match=\"" + constraint + "\" type=\"ST\"/></LocValReq>" //
+ "<LocValReq id=\"poi\" maxNr=\"10\"><ReqLoc match=\"" + constraint + "\" type=\"POI\"/></LocValReq>";
InputStream is = null;
try
{
is = ParserUtils.scrapeInputStream(autocompleteUri, request);
is = ParserUtils.scrapeInputStream(apiUri, wrap(request));
final List<Location> results = new ArrayList<Location>();
@ -85,32 +125,25 @@ public abstract class AbstractHafasProvider implements NetworkProvider
while (XmlPullUtil.test(pp, "Station"))
{
final String name = pp.getAttributeValue(null, "name");
final int id = Integer.parseInt(pp.getAttributeValue(null, "externalStationNr"));
final int x = Integer.parseInt(pp.getAttributeValue(null, "x"));
final int y = Integer.parseInt(pp.getAttributeValue(null, "y"));
results.add(new Location(LocationType.STATION, id, y, x, name));
results.add(parseLocation(pp));
XmlPullUtil.skipTree(pp);
XmlPullUtil.next(pp);
}
XmlPullUtil.exit(pp);
XmlPullUtil.require(pp, "LocValRes");
XmlPullUtil.requireAttr(pp, "id", "poi");
XmlPullUtil.enter(pp);
while (XmlPullUtil.test(pp, "Poi"))
{
final String name = pp.getAttributeValue(null, "name");
final int x = Integer.parseInt(pp.getAttributeValue(null, "x"));
final int y = Integer.parseInt(pp.getAttributeValue(null, "y"));
results.add(new Location(LocationType.POI, 0, y, x, name));
XmlPullUtil.skipTree(pp);
}
XmlPullUtil.exit(pp);
// XmlPullUtil.require(pp, "LocValRes");
// XmlPullUtil.requireAttr(pp, "id", "poi");
// XmlPullUtil.enter(pp);
//
// while (XmlPullUtil.test(pp, "Poi"))
// {
// results.add(parsePoi(pp));
//
// XmlPullUtil.next(pp);
// }
//
// XmlPullUtil.exit(pp);
return results;
}
@ -129,6 +162,371 @@ public abstract class AbstractHafasProvider implements NetworkProvider
}
}
public QueryConnectionsResult queryConnections(Location from, Location via, Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
if (from.type == LocationType.ANY)
{
final List<Location> autocompletes = autocompleteStations(from.name);
if (autocompletes.isEmpty())
return new QueryConnectionsResult(QueryConnectionsResult.Status.NO_CONNECTIONS); // TODO
if (autocompletes.size() > 1)
return new QueryConnectionsResult(autocompletes, null, null);
from = autocompletes.get(0);
}
if (via != null && via.type == LocationType.ANY)
{
final List<Location> autocompletes = autocompleteStations(via.name);
if (autocompletes.isEmpty())
return new QueryConnectionsResult(QueryConnectionsResult.Status.NO_CONNECTIONS); // TODO
if (autocompletes.size() > 1)
return new QueryConnectionsResult(null, autocompletes, null);
via = autocompletes.get(0);
}
if (to.type == LocationType.ANY)
{
final List<Location> autocompletes = autocompleteStations(to.name);
if (autocompletes.isEmpty())
return new QueryConnectionsResult(QueryConnectionsResult.Status.NO_CONNECTIONS); // TODO
if (autocompletes.size() > 1)
return new QueryConnectionsResult(null, null, autocompletes);
to = autocompletes.get(0);
}
final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
final DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm");
final String request = "<ConReq>" //
+ "<Start>" + location(from) + "<Prod bike=\"0\" couchette=\"0\" direct=\"0\" sleeper=\"0\"/></Start>" //
+ (via != null ? "<Via>" + location(via) + "</Via>" : "") //
+ "<Dest>" + location(to) + "</Dest>" //
+ "<ReqT a=\"" + (dep ? 0 : 1) + "\" date=\"" + DATE_FORMAT.format(date) + "\" time=\"" + TIME_FORMAT.format(date) + "\"/>" //
+ "<RFlags b=\"0\" chExtension=\"0\" f=\"4\" sMode=\"N\"/>" //
+ "</ConReq>";
// System.out.println(request);
// System.out.println(ParserUtils.scrape(apiUri, true, wrap(request), null, false));
InputStream is = null;
try
{
is = ParserUtils.scrapeInputStream(apiUri, wrap(request));
final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
final XmlPullParser pp = factory.newPullParser();
pp.setInput(is, DEFAULT_ENCODING);
XmlPullUtil.jump(pp, "ConRes");
XmlPullUtil.enter(pp);
if (pp.getName().equals("Err"))
{
final String code = XmlPullUtil.attr(pp, "code");
if (code.equals("K9380"))
return QueryConnectionsResult.TOO_CLOSE;
if (code.equals("K9220")) // Nearby to the given address stations could not be found
return QueryConnectionsResult.NO_CONNECTIONS;
throw new IllegalStateException("error " + code + " " + XmlPullUtil.attr(pp, "text"));
}
XmlPullUtil.require(pp, "ConResCtxt");
final String sessionId = XmlPullUtil.text(pp);
XmlPullUtil.require(pp, "ConnectionList");
XmlPullUtil.enter(pp);
final List<Connection> connections = new ArrayList<Connection>();
while (XmlPullUtil.test(pp, "Connection"))
{
final String id = XmlPullUtil.attr(pp, "id");
XmlPullUtil.enter(pp);
while (pp.getName().equals("RtStateList"))
XmlPullUtil.next(pp);
XmlPullUtil.require(pp, "Overview");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Date");
final Date currentDate = DATE_FORMAT.parse(XmlPullUtil.text(pp));
XmlPullUtil.exit(pp);
XmlPullUtil.require(pp, "ConSectionList");
XmlPullUtil.enter(pp);
final List<Connection.Part> parts = new ArrayList<Connection.Part>(4);
Date firstDepartureTime = null;
Date lastArrivalTime = null;
while (XmlPullUtil.test(pp, "ConSection"))
{
XmlPullUtil.enter(pp);
// departure
XmlPullUtil.require(pp, "Departure");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "BasicStop");
XmlPullUtil.enter(pp);
while (pp.getName().equals("StAttrList"))
XmlPullUtil.next(pp);
Location departure;
if (pp.getName().equals("Station"))
departure = parseLocation(pp);
else if (pp.getName().equals("Poi"))
departure = parsePoi(pp);
else
throw new IllegalStateException("cannot parse: " + pp.getName());
XmlPullUtil.next(pp);
XmlPullUtil.require(pp, "Dep");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Time");
final Date departureTime = ParserUtils.joinDateTime(currentDate, TIME_FORMAT.parse(XmlPullUtil.text(pp).substring(3, 8)));
XmlPullUtil.require(pp, "Platform");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Text");
String departurePos = XmlPullUtil.text(pp).trim();
if (departurePos.length() == 0)
departurePos = null;
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
// journey
String line = null;
String direction = null;
int min = 0;
final String tag = pp.getName();
if (tag.equals("Journey"))
{
XmlPullUtil.enter(pp);
while (pp.getName().equals("JHandle"))
XmlPullUtil.next(pp);
XmlPullUtil.require(pp, "JourneyAttributeList");
XmlPullUtil.enter(pp);
String name = null;
String category = null;
while (XmlPullUtil.test(pp, "JourneyAttribute"))
{
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Attribute");
final String attrName = XmlPullUtil.attr(pp, "type");
XmlPullUtil.enter(pp);
final String attrValue = parseAttributeVariant(pp, "NORMAL");
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
if ("NAME".equals(attrName))
name = attrValue;
else if ("CATEGORY".equals(attrName))
category = attrValue;
else if ("DIRECTION".equals(attrName))
direction = attrValue;
}
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
line = _normalizeLine(category, name);
}
else if (tag.equals("Walk") || tag.equals("Transfer"))
{
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Duration");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Time");
min = parseDuration(XmlPullUtil.text(pp).substring(3, 8));
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
}
else
{
throw new IllegalStateException("cannot handle: " + pp.getName());
}
// arrival
XmlPullUtil.require(pp, "Arrival");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "BasicStop");
XmlPullUtil.enter(pp);
while (pp.getName().equals("StAttrList"))
XmlPullUtil.next(pp);
Location arrival;
if (pp.getName().equals("Station"))
arrival = parseLocation(pp);
else if (pp.getName().equals("Poi"))
arrival = parsePoi(pp);
else
throw new IllegalStateException("cannot parse: " + pp.getName());
XmlPullUtil.next(pp);
XmlPullUtil.require(pp, "Arr");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Time");
final Date arrivalTime = ParserUtils.joinDateTime(currentDate, TIME_FORMAT.parse(XmlPullUtil.text(pp).substring(3, 8)));
XmlPullUtil.require(pp, "Platform");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Text");
String arrivalPos = XmlPullUtil.text(pp).trim();
if (arrivalPos.length() == 0)
arrivalPos = null;
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
if (min == 0 || line != null)
{
parts.add(new Connection.Trip(line, lineColors(line), 0, direction, departureTime, departurePos, departure.id,
departure.name, arrivalTime, arrivalPos, arrival.id, arrival.name));
}
else
{
if (parts.size() > 0 && parts.get(parts.size() - 1) instanceof Connection.Footway)
{
final Connection.Footway lastFootway = (Connection.Footway) parts.remove(parts.size() - 1);
parts.add(new Connection.Footway(lastFootway.min + min, lastFootway.departureId, lastFootway.departure, arrival.id,
arrival.name));
}
else
{
parts.add(new Connection.Footway(min, departure.id, departure.name, arrival.id, arrival.name));
}
}
if (firstDepartureTime == null)
firstDepartureTime = departureTime;
lastArrivalTime = arrivalTime;
}
XmlPullUtil.exit(pp);
XmlPullUtil.exit(pp);
connections.add(new Connection(id, null, firstDepartureTime, lastArrivalTime, null, null, 0, null, 0, null, parts));
}
XmlPullUtil.exit(pp);
return new QueryConnectionsResult(null, from, via, to, null, null, connections);
}
catch (final XmlPullParserException x)
{
throw new RuntimeException(x);
}
catch (final SocketTimeoutException x)
{
throw new RuntimeException(x);
}
catch (final ParseException x)
{
throw new RuntimeException(x);
}
finally
{
if (is != null)
is.close();
}
}
private final String parseAttributeVariant(final XmlPullParser pp, final String type) throws XmlPullParserException, IOException
{
String value = null;
while (XmlPullUtil.test(pp, "AttributeVariant"))
{
if (type.equals(XmlPullUtil.attr(pp, "type")))
{
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "Text");
value = XmlPullUtil.text(pp).trim();
XmlPullUtil.exit(pp);
}
else
{
XmlPullUtil.next(pp);
}
}
return value;
}
private static final Pattern P_DURATION = Pattern.compile("(\\d+):(\\d{2})");
private final int parseDuration(final String str)
{
final Matcher m = P_DURATION.matcher(str);
if (m.matches())
return Integer.parseInt(m.group(1)) * 60 + Integer.parseInt(m.group(2));
else
throw new IllegalArgumentException("cannot parse duration: " + str);
}
private final String location(final Location location)
{
if (location.type == LocationType.STATION && location.id != 0)
return "<Station externalId=\"" + location.id + "\" />";
if (location.type == LocationType.POI && (location.lat != 0 || location.lon != 0))
return "<Poi type=\"WGS84\" x=\"" + location.lon + "\" y=\"" + location.lat + "\" />";
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
private final String _normalizeLine(final String type, final String name)
{
final String normalizedType = type.split(" ", 2)[0];
final String normalizedName = normalizeWhitespace(name);
if ("THALYS".equals(normalizedType))
return "I" + normalizedName;
if ("IC".equals(normalizedType))
return "I" + normalizedName;
if ("EN".equals(normalizedType))
return "I" + normalizedName;
if ("OEC".equals(normalizedType))
return "I" + normalizedName;
if ("R".equals(normalizedType))
return "R" + normalizedName;
if ("RE".equals(normalizedType))
return "R" + normalizedName;
if ("IR".equals(normalizedType))
return "R" + normalizedName;
if ("Tramway".equals(normalizedType))
return "T" + normalizedName;
if ("BUS".equals(normalizedType))
return "B" + normalizedName;
if ("L".equals(normalizedType))
return "?" + normalizedName;
if ("NZ".equals(normalizedType))
return "?" + normalizedName;
throw new IllegalStateException("cannot normalize type '" + normalizedType + "' (" + type + ") name '" + normalizedName + "'");
}
private final static Pattern P_WHITESPACE = Pattern.compile("\\s+");
private final String normalizeWhitespace(final String str)
{
return P_WHITESPACE.matcher(str).replaceAll("");
}
public QueryConnectionsResult queryMoreConnections(String uri) throws IOException
{
throw new UnsupportedOperationException();
}
public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException
{
throw new UnsupportedOperationException();
}
private final static Pattern P_NEARBY_COARSE = Pattern.compile("<tr class=\"(zebra[^\"]*)\">(.*?)</tr>", Pattern.DOTALL);
private final static Pattern P_NEARBY_FINE_COORDS = Pattern
.compile("&REQMapRoute0\\.Location0\\.X=(-?\\d+)&REQMapRoute0\\.Location0\\.Y=(-?\\d+)&");
@ -200,7 +598,7 @@ public abstract class AbstractHafasProvider implements NetworkProvider
if (normalizedType != 0)
return normalizedType + strippedLine;
throw new IllegalStateException("cannot normalize type " + type + " line " + line);
throw new IllegalStateException("cannot normalize type '" + type + "' line '" + line + "'");
}
protected abstract char normalizeType(String type);

View file

@ -48,7 +48,7 @@ public class NasaProvider extends AbstractHafasProvider
public NasaProvider()
{
super(null, null, null);
super(null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
@ -250,17 +250,20 @@ public class NasaProvider extends AbstractHafasProvider
return 0;
}
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
public QueryConnectionsResult queryMoreConnections(String uri) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException
{
throw new UnsupportedOperationException();

View file

@ -50,7 +50,7 @@ public class OebbProvider extends AbstractHafasProvider
public OebbProvider()
{
super(null, null, null);
super(null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
@ -233,6 +233,7 @@ public class OebbProvider extends AbstractHafasProvider
"<select.*? name=\"(REQ0JourneyStopsS0K|REQ0JourneyStopsZ0K|REQ0JourneyStops1\\.0K)\"[^>]*>\n(.*?)</select>", Pattern.DOTALL);
private static final Pattern P_ADDRESSES = Pattern.compile("<option[^>]*>\\s*([^<\\[]*)(?:\\[[^\\[]*\\])?\\s*</option>", Pattern.DOTALL);
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
@ -293,6 +294,7 @@ public class OebbProvider extends AbstractHafasProvider
return queryConnections(baseUri, page);
}
@Override
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri, false, null, null, true);
@ -483,6 +485,7 @@ public class OebbProvider extends AbstractHafasProvider
}
}
@Override
public GetConnectionDetailsResult getConnectionDetails(final String connectionUri) throws IOException
{
throw new UnsupportedOperationException();

View file

@ -53,7 +53,7 @@ public class RmvProvider extends AbstractHafasProvider
public RmvProvider()
{
super(null, null, null);
super(null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
@ -184,6 +184,7 @@ public class RmvProvider extends AbstractHafasProvider
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile(
"(mehrfach vorhanden oder identisch)|(keine Verbindung gefunden werden)|(derzeit nur Ausk&#252;nfte vom)", Pattern.CASE_INSENSITIVE);
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
@ -249,6 +250,7 @@ public class RmvProvider extends AbstractHafasProvider
+ "(?:&nbsp;(.+?))?" //
, Pattern.DOTALL);
@Override
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
@ -333,6 +335,7 @@ public class RmvProvider extends AbstractHafasProvider
+ "- <b>(.*?)" // arrival
, Pattern.DOTALL);
@Override
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);

View file

@ -45,12 +45,13 @@ public class SbbProvider extends AbstractHafasProvider
{
public static final String NETWORK_ID = "fahrplan.sbb.ch";
private static final String API_BASE = "http://fahrplan.sbb.ch/bin/";
private static final String API_URI = "http://fahrplan.sbb.ch/bin/extxml.exe";
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public SbbProvider()
public SbbProvider(final String accessId)
{
super("http://fahrplan.sbb.ch/bin/extxml.exe", "iPhone3.1", "MJXZ841ZfsmqqmSymWhBPy5dMNoqoGsHInHbWJQ5PTUZOJ1rLTkn8vVZOZDFfSe");
super(API_URI, accessId);
}
public boolean hasCapabilities(final Capability... capabilities)
@ -131,6 +132,7 @@ public class SbbProvider extends AbstractHafasProvider
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern
.compile("(mehrfach vorhanden oder identisch)|(keine Verbindung gefunden werden)|(liegt nach dem Ende der Fahrplanperiode|liegt vor Beginn der Fahrplanperiode)");
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
@ -185,6 +187,7 @@ public class SbbProvider extends AbstractHafasProvider
return queryConnections(uri, page);
}
@Override
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
@ -293,6 +296,7 @@ public class SbbProvider extends AbstractHafasProvider
+ "- ([^<]*) -\n" // destination
, Pattern.DOTALL);
@Override
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);

View file

@ -27,9 +27,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.GetConnectionDetailsResult;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.util.ParserUtils;
@ -43,17 +40,17 @@ public class SncbProvider extends AbstractHafasProvider
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
private static final String AUTOCOMPLETE_URI = "http://hari.b-rail.be/Hafas/bin/extxml.exe";
private static final String API_URI = "http://hari.b-rail.be/Hafas/bin/extxml.exe";
public SncbProvider()
{
super(AUTOCOMPLETE_URI, "irail", null);
super(API_URI, null);
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.DEPARTURES)
if (capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
@ -67,22 +64,6 @@ public class SncbProvider extends AbstractHafasProvider
return String.format(NEARBY_URI, stationId);
}
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
throw new UnsupportedOperationException();
}
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
throw new UnsupportedOperationException();
}
public GetConnectionDetailsResult getConnectionDetails(final String connectionUri) throws IOException
{
throw new UnsupportedOperationException();
}
public String departuresQueryUri(final String stationId, final int maxDepartures)
{
final StringBuilder uri = new StringBuilder();

View file

@ -48,7 +48,7 @@ public class VgsProvider extends AbstractHafasProvider
public VgsProvider()
{
super(null, null, null);
super(null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
@ -247,17 +247,20 @@ public class VgsProvider extends AbstractHafasProvider
return 0;
}
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
public QueryConnectionsResult queryMoreConnections(String uri) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException
{
throw new UnsupportedOperationException();

View file

@ -32,6 +32,7 @@ public final class XmlPullUtil
/**
* enters current tag
*
* @throws IOException
*/
public static void enter(final XmlPullParser pp) throws XmlPullParserException, IOException
@ -40,13 +41,25 @@ public final class XmlPullUtil
throw new IllegalStateException("expecting start tag to enter");
if (pp.isEmptyElementTag())
throw new IllegalStateException("cannot enter empty tag");
pp.next();
}
public static void exit(final XmlPullParser pp) throws XmlPullParserException, IOException
{
while (pp.getEventType() != XmlPullParser.END_TAG)
{
if (pp.getEventType() == XmlPullParser.START_TAG)
next(pp);
else if (pp.getEventType() == XmlPullParser.TEXT)
pp.next();
else
throw new IllegalStateException();
}
if (pp.getEventType() != XmlPullParser.END_TAG)
throw new IllegalStateException("expecting end tag to exit");
pp.next();
}
@ -55,7 +68,7 @@ public final class XmlPullUtil
return pp.getEventType() == XmlPullParser.START_TAG && pp.getName().equals(tagName);
}
public static void skipTree(final XmlPullParser pp) throws XmlPullParserException, IOException
public static void next(final XmlPullParser pp) throws XmlPullParserException, IOException
{
skipSubTree(pp);
pp.next();
@ -82,6 +95,22 @@ public final class XmlPullUtil
throw new IllegalStateException("cannot find " + attrName + "=\"" + requiredValue + "\" />");
}
public static String text(final XmlPullParser pp) throws XmlPullParserException, IOException
{
if (pp.getEventType() != XmlPullParser.START_TAG || pp.isEmptyElementTag())
throw new IllegalStateException("expecting start tag to get text from");
enter(pp);
String text = "";
if (pp.getEventType() == XmlPullParser.TEXT)
text = pp.getText();
exit(pp);
return text;
}
/**
* Return value of attribute with given name and no namespace.
*/

View file

@ -36,7 +36,7 @@ import de.schildbach.pte.dto.QueryDeparturesResult;
*/
public class SbbProviderLiveTest
{
private SbbProvider provider = new SbbProvider();
private SbbProvider provider = new SbbProvider(Secrets.SBB_ACCESS_ID);
private static final String ALL_PRODUCTS = "IRSUTBFC";
@Test
@ -74,8 +74,8 @@ public class SbbProviderLiveTest
@Test
public void shortConnection() throws Exception
{
final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ANY, 0, 0, 0, "Zürich!"), null, new Location(
LocationType.ANY, 0, 0, 0, "Bern"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 8503000, 0, 0, "Zürich HB"), null,
new Location(LocationType.STATION, 8507785, 0, 0, "Bern, Hauptbahnhof"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
System.out.println(result);
final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater);
System.out.println(moreResult);

View file

@ -16,13 +16,17 @@
*/
package de.schildbach.pte.live;
import java.util.Date;
import java.util.List;
import org.junit.Test;
import de.schildbach.pte.SncbProvider;
import de.schildbach.pte.NetworkProvider.WalkSpeed;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryConnectionsResult;
/**
* @author Andreas Schildbach
@ -47,6 +51,24 @@ public class SncbProviderLiveTest
System.out.println();
}
@Test
public void shortConnection() throws Exception
{
final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 100024, 0, 0, null), null, new Location(
LocationType.STATION, 100066, 0, 0, null), new Date(), true, null, WalkSpeed.FAST);
System.out.println(result.status + " " + result.connections);
}
@Test
public void longConnection() throws Exception
{
final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 100024, 0, 0, null), null, new Location(
LocationType.STATION, 103624, 0, 0, null), new Date(), true, null, WalkSpeed.FAST);
System.out.println(result.status + " " + result.connections);
}
@Test
public void nearbyStation() throws Exception
{