scan nearby stations for Berlin

git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@395 0924bc21-9374-b0fa-ee44-9ff1593b38f0
This commit is contained in:
andreas.schildbach@gmail.com 2010-12-15 22:46:54 +00:00
parent 028008cc08
commit 4f18a77433
4 changed files with 147 additions and 11 deletions

View file

@ -922,7 +922,7 @@ public abstract class AbstractHafasProvider implements NetworkProvider
LINES.put('?', new int[] { Color.DKGRAY, Color.WHITE }); LINES.put('?', new int[] { Color.DKGRAY, Color.WHITE });
} }
public final int[] lineColors(final String line) public int[] lineColors(final String line)
{ {
if (line.length() == 0) if (line.length() == 0)
return null; return null;

View file

@ -42,6 +42,7 @@ import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryConnectionsResult; import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.QueryDeparturesResult; import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status; import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.Station;
import de.schildbach.pte.exception.SessionExpiredException; import de.schildbach.pte.exception.SessionExpiredException;
import de.schildbach.pte.util.Color; import de.schildbach.pte.util.Color;
import de.schildbach.pte.util.ParserUtils; import de.schildbach.pte.util.ParserUtils;
@ -49,7 +50,7 @@ import de.schildbach.pte.util.ParserUtils;
/** /**
* @author Andreas Schildbach * @author Andreas Schildbach
*/ */
public final class BvgProvider implements NetworkProvider public final class BvgProvider extends AbstractHafasProvider
{ {
public static final String NETWORK_ID = "mobil.bvg.de"; public static final String NETWORK_ID = "mobil.bvg.de";
@ -57,6 +58,12 @@ public final class BvgProvider implements NetworkProvider
private static final long PARSER_DAY_ROLLDOWN_THRESHOLD_MS = 6 * 60 * 60 * 1000; private static final long PARSER_DAY_ROLLDOWN_THRESHOLD_MS = 6 * 60 * 60 * 1000;
private static final String BVG_BASE_URL = "http://mobil.bvg.de"; private static final String BVG_BASE_URL = "http://mobil.bvg.de";
private static final String API_BASE = "http://mobil.bvg.de/Fahrinfo/bin/";
public BvgProvider()
{
super(null, null);
}
public boolean hasCapabilities(final Capability... capabilities) public boolean hasCapabilities(final Capability... capabilities)
{ {
@ -72,6 +79,7 @@ public final class BvgProvider implements NetworkProvider
private static final Pattern P_MULTI_NAME = Pattern.compile("<a href=\\\"/Fahrinfo/bin/stboard\\.bin/dox.*?input=(\\d+)&.*?\">\\s*(.*?)\\s*</a>", private static final Pattern P_MULTI_NAME = Pattern.compile("<a href=\\\"/Fahrinfo/bin/stboard\\.bin/dox.*?input=(\\d+)&.*?\">\\s*(.*?)\\s*</a>",
Pattern.DOTALL); Pattern.DOTALL);
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{ {
final List<Location> results = new ArrayList<Location>(); final List<Location> results = new ArrayList<Location>();
@ -93,10 +101,72 @@ public final class BvgProvider implements NetworkProvider
return results; return results;
} }
private final String NEARBY_URI = API_BASE + "stboard.bin/dn?distance=50&near&input=%s";
@Override
protected String nearbyStationUri(final String stationId)
{
return String.format(NEARBY_URI, ParserUtils.urlEncode(stationId));
}
private final static Pattern P_NEARBY_OWN = Pattern
.compile("/Stadtplan/index.*?location=(\\d+),HST,WGS84,(-?\\d+\\.\\d+),(-?\\d+\\.\\d+)&amp;label=([^\"]*)\"");
private final static Pattern P_NEARBY_PAGE = Pattern.compile("<table class=\"ivuTableOverview\".*?<tbody>(.*?)</tbody>", Pattern.DOTALL);
private final static Pattern P_NEARBY_COARSE = Pattern.compile("<tr>(.*?)</tr>", Pattern.DOTALL);
private final static Pattern P_NEARBY_FINE_LOCATION = Pattern.compile("input=(\\d+)&[^\"]*\">([^<]*)<");
@Override
public NearbyStationsResult nearbyStations(final String stationId, final int lat, final int lon, final int maxDistance, final int maxStations) public NearbyStationsResult nearbyStations(final String stationId, final int lat, final int lon, final int maxDistance, final int maxStations)
throws IOException throws IOException
{ {
throw new UnsupportedOperationException(); if (stationId == null)
throw new IllegalArgumentException("stationId must be given");
final List<Station> stations = new ArrayList<Station>();
final String uri = nearbyStationUri(stationId);
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mOwn = P_NEARBY_OWN.matcher(page);
if (mOwn.find())
{
final int parsedId = Integer.parseInt(mOwn.group(1));
final int parsedLon = (int) (Float.parseFloat(mOwn.group(2)) * 1E6);
final int parsedLat = (int) (Float.parseFloat(mOwn.group(3)) * 1E6);
final String parsedName = ParserUtils.urlDecode(mOwn.group(4), "ISO-8859-1");
stations.add(new Station(parsedId, parsedName, parsedLat, parsedLon, 0, null, null));
}
final Matcher mPage = P_NEARBY_PAGE.matcher(page);
if (mPage.find())
{
final Matcher mCoarse = P_NEARBY_COARSE.matcher(mPage.group(1));
while (mCoarse.find())
{
final Matcher mFineLocation = P_NEARBY_FINE_LOCATION.matcher(mCoarse.group(1));
if (mFineLocation.find())
{
final int parsedId = Integer.parseInt(mFineLocation.group(1));
final String parsedName = ParserUtils.resolveEntities(mFineLocation.group(2));
stations.add(new Station(parsedId, parsedName, 0, 0, 0, null, null));
}
else
{
throw new IllegalArgumentException("cannot parse '" + mCoarse.group(1) + "' on " + uri);
}
}
if (maxStations == 0 || maxStations >= stations.size())
return new NearbyStationsResult(stations);
else
return new NearbyStationsResult(stations.subList(0, maxStations));
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + uri);
}
} }
public static final String STATION_URL_CONNECTION = "http://mobil.bvg.de/Fahrinfo/bin/query.bin/dox"; public static final String STATION_URL_CONNECTION = "http://mobil.bvg.de/Fahrinfo/bin/query.bin/dox";
@ -183,6 +253,7 @@ public final class BvgProvider implements NetworkProvider
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern
.compile("(zu dicht beieinander|mehrfach vorhanden oder identisch)|(keine geeigneten Haltestellen)|(keine Verbindung gefunden)|(derzeit nur Ausk&#252;nfte vom)|(zwischenzeitlich nicht mehr gespeichert)"); .compile("(zu dicht beieinander|mehrfach vorhanden oder identisch)|(keine geeigneten Haltestellen)|(keine Verbindung gefunden)|(derzeit nur Ausk&#252;nfte vom)|(zwischenzeitlich nicht mehr gespeichert)");
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, 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 final String products, final WalkSpeed walkSpeed) throws IOException
{ {
@ -216,6 +287,7 @@ public final class BvgProvider implements NetworkProvider
} }
} }
@Override
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{ {
final CharSequence page = ParserUtils.scrape(uri); final CharSequence page = ParserUtils.scrape(uri);
@ -321,6 +393,7 @@ public final class BvgProvider implements NetworkProvider
+ "<strong>(.*?)</strong>|<a href=\"/Stadtplan.*?WGS84,(\\d+),(\\d+)&.*?\">([^<]*)</a>|<strong>([^<]*)</strong>).*?" // arrival + "<strong>(.*?)</strong>|<a href=\"/Stadtplan.*?WGS84,(\\d+),(\\d+)&.*?\">([^<]*)</a>|<strong>([^<]*)</strong>).*?" // arrival
+ ").*?", Pattern.DOTALL); + ").*?", Pattern.DOTALL);
@Override
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
{ {
final CharSequence page = ParserUtils.scrape(uri); final CharSequence page = ParserUtils.scrape(uri);
@ -648,15 +721,16 @@ public final class BvgProvider implements NetworkProvider
throw new IllegalStateException("cannot normalize line " + line); throw new IllegalStateException("cannot normalize line " + line);
} }
@Override
protected char normalizeType(final String type)
{
throw new UnsupportedOperationException();
}
private static final Map<String, int[]> LINES = new HashMap<String, int[]>(); private static final Map<String, int[]> LINES = new HashMap<String, int[]>();
static static
{ {
LINES.put("I", new int[] { Color.WHITE, Color.RED, Color.RED }); // generic
LINES.put("R", new int[] { Color.WHITE, Color.RED, Color.RED }); // generic
LINES.put("S", new int[] { Color.parseColor("#006e34"), Color.WHITE }); // generic
LINES.put("U", new int[] { Color.parseColor("#003090"), Color.WHITE }); // generic
LINES.put("SS1", new int[] { Color.rgb(221, 77, 174), Color.WHITE }); LINES.put("SS1", new int[] { Color.rgb(221, 77, 174), Color.WHITE });
LINES.put("SS2", new int[] { Color.rgb(16, 132, 73), Color.WHITE }); LINES.put("SS2", new int[] { Color.rgb(16, 132, 73), Color.WHITE });
LINES.put("SS25", new int[] { Color.rgb(16, 132, 73), Color.WHITE }); LINES.put("SS25", new int[] { Color.rgb(16, 132, 73), Color.WHITE });
@ -764,10 +838,13 @@ public final class BvgProvider implements NetworkProvider
LINES.put("RRB93", new int[] { Color.parseColor("#A7653F"), Color.WHITE }); LINES.put("RRB93", new int[] { Color.parseColor("#A7653F"), Color.WHITE });
} }
@Override
public int[] lineColors(final String line) public int[] lineColors(final String line)
{ {
if (line.length() == 0) final int[] lineColors = LINES.get(line);
return null; if (lineColors != null)
return LINES.get(line); return lineColors;
else
return super.lineColors(line);
} }
} }

View file

@ -27,6 +27,7 @@ import java.io.Writer;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -360,6 +361,18 @@ public final class ParserUtils
} }
} }
public static String urlDecode(final String str, final String enc)
{
try
{
return URLDecoder.decode(str, enc);
}
catch (final UnsupportedEncodingException x)
{
throw new RuntimeException(x);
}
}
public static <T> T selectNotNull(final T... groups) public static <T> T selectNotNull(final T... groups)
{ {
T selected = null; T selected = null;

View file

@ -0,0 +1,46 @@
/*
* Copyright 2010 the original author or authors.
*
* 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 de.schildbach.pte.live;
import org.junit.Test;
import de.schildbach.pte.BvgProvider;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
/**
* @author Andreas Schildbach
*/
public class BvgProviderLiveTest
{
private BvgProvider provider = new BvgProvider();
@Test
public void nearbyStation() throws Exception
{
final NearbyStationsResult result = provider.nearbyStations("9415052", 0, 0, 0, 0);
System.out.println(result.stations.size() + " " + result.stations);
}
@Test
public void departures() throws Exception
{
final QueryDeparturesResult queryDepartures = provider.queryDepartures("309557", 0);
System.out.println(queryDepartures.departures);
}
}