autocomplete using XML-interface for Switzerland and Belgium

git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@300 0924bc21-9374-b0fa-ee44-9ff1593b38f0
This commit is contained in:
andreas.schildbach 2010-10-16 22:15:55 +00:00
parent 824bab1b5e
commit 06712bf0eb
9 changed files with 165 additions and 41 deletions

View file

@ -18,6 +18,8 @@
package de.schildbach.pte;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -25,16 +27,108 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.Station;
import de.schildbach.pte.util.Color;
import de.schildbach.pte.util.ParserUtils;
import de.schildbach.pte.util.XmlPullUtil;
/**
* @author Andreas Schildbach
*/
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 accessId;
public AbstractHafasProvider(final String autocompleteUri, final String prod, final String accessId)
{
this.autocompleteUri = autocompleteUri;
this.prod = prod;
this.accessId = accessId;
}
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>";
InputStream is = null;
try
{
is = ParserUtils.scrapeInputStream(autocompleteUri, request);
final List<Location> results = new ArrayList<Location>();
final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
final XmlPullParser pp = factory.newPullParser();
pp.setInput(is, DEFAULT_ENCODING);
XmlPullUtil.jump(pp, "ResC");
XmlPullUtil.enter(pp);
XmlPullUtil.require(pp, "LocValRes");
XmlPullUtil.requireAttr(pp, "id", "station");
XmlPullUtil.enter(pp);
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));
XmlPullUtil.skipTree(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);
return results;
}
catch (final XmlPullParserException x)
{
throw new RuntimeException(x);
}
catch (final SocketTimeoutException x)
{
throw new RuntimeException(x);
}
finally
{
if (is != null)
is.close();
}
}
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+)&");

View file

@ -46,6 +46,11 @@ public class NasaProvider extends AbstractHafasProvider
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public NasaProvider()
{
super(null, null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
@ -55,6 +60,7 @@ public class NasaProvider extends AbstractHafasProvider
return false;
}
@Override
public List<Location> autocompleteStations(CharSequence constraint) throws IOException
{
throw new UnsupportedOperationException();

View file

@ -48,6 +48,11 @@ public class OebbProvider extends AbstractHafasProvider
public static final String NETWORK_ID = "fahrplan.oebb.at";
private static final String API_BASE = "http://fahrplan.oebb.at/bin/";
public OebbProvider()
{
super(null, null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
@ -63,6 +68,7 @@ public class OebbProvider extends AbstractHafasProvider
private static final Pattern P_AUTOCOMPLETE_JSON = Pattern.compile("SLs\\.sls=(.*?);SLs\\.showSuggestion\\(\\);", Pattern.DOTALL);
private static final Pattern P_AUTOCOMPLETE_ID = Pattern.compile(".*?@L=(\\d+)@.*?");
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));

View file

@ -51,6 +51,11 @@ public class RmvProvider extends AbstractHafasProvider
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public RmvProvider()
{
super(null, null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
@ -66,6 +71,7 @@ public class RmvProvider extends AbstractHafasProvider
private static final Pattern P_MULTI_NAME = Pattern.compile("<a href=\"/auskunft/bin/jp/stboard.exe/dox.*?input=(\\d+)&.*?\">\\s*(.*?)\\s*</a>",
Pattern.DOTALL);
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final CharSequence page = ParserUtils.scrape(NAME_URL + ParserUtils.urlEncode(constraint.toString()));

View file

@ -48,6 +48,11 @@ public class SbbProvider extends AbstractHafasProvider
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public SbbProvider()
{
super("http://fahrplan.sbb.ch/bin/extxml.exe", "iPhone3.1", "MJXZ841ZfsmqqmSymWhBPy5dMNoqoGsHInHbWJQ5PTUZOJ1rLTkn8vVZOZDFfSe");
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
@ -57,35 +62,6 @@ public class SbbProvider extends AbstractHafasProvider
return false;
}
private static final String NAME_URL = API_BASE + "bhftafel.exe/dox?input=";
private static final Pattern P_SINGLE_NAME = Pattern.compile(".*?<input type=\"hidden\" name=\"input\" value=\"(.+?)#(\\d+)\" />.*",
Pattern.DOTALL);
private static final Pattern P_MULTI_NAME = Pattern.compile("<a href=\"http://fahrplan\\.sbb\\.ch/bin/bhftafel\\.exe/dox\\?input=(\\d+).*?\">\n?" //
+ "(.*?)\n?" //
+ "</a>", Pattern.DOTALL);
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final CharSequence page = ParserUtils.scrape(NAME_URL + ParserUtils.urlEncode(constraint.toString()));
final List<Location> results = new ArrayList<Location>();
final Matcher mSingle = P_SINGLE_NAME.matcher(page);
if (mSingle.matches())
{
results.add(new Location(LocationType.STATION, Integer.parseInt(mSingle.group(2)), 0, 0, ParserUtils.resolveEntities(mSingle.group(1))));
}
else
{
final Matcher mMulti = P_MULTI_NAME.matcher(page);
while (mMulti.find())
results
.add(new Location(LocationType.STATION, Integer.parseInt(mMulti.group(1)), 0, 0, ParserUtils.resolveEntities(mMulti.group(2))));
}
return results;
}
private final static String NEARBY_URI = API_BASE + "bhftafel.exe/dn?input=%s&distance=50&near=Anzeigen";
@Override

View file

@ -43,6 +43,13 @@ 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";
public SncbProvider()
{
super(AUTOCOMPLETE_URI, "irail", null);
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
@ -52,11 +59,6 @@ public class SncbProvider extends AbstractHafasProvider
return false;
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
throw new UnsupportedOperationException();
}
private final String NEARBY_URI = "http://hari.b-rail.be/HAFAS/bin/stboard.exe/en?input=%s&distance=50&near=Anzeigen";
@Override

View file

@ -46,6 +46,11 @@ public class VgsProvider extends AbstractHafasProvider
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public VgsProvider()
{
super(null, null, null);
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
@ -55,6 +60,7 @@ public class VgsProvider extends AbstractHafasProvider
return false;
}
@Override
public List<Location> autocompleteStations(CharSequence constraint) throws IOException
{
throw new UnsupportedOperationException();

View file

@ -39,6 +39,22 @@ public class SbbProviderLiveTest
private SbbProvider provider = new SbbProvider();
private static final String ALL_PRODUCTS = "IRSUTBFC";
@Test
public void autoComplete() throws Exception
{
final List<Location> autocompletes = provider.autocompleteStations("haupt");
list(autocompletes);
}
private void list(final List<Location> autocompletes)
{
System.out.print(autocompletes.size() + " ");
for (final Location autocomplete : autocompletes)
System.out.print(autocomplete.toDebugString() + " ");
System.out.println();
}
@Test
public void nearbyStation() throws Exception
{
@ -90,11 +106,4 @@ public class SbbProviderLiveTest
for (final Connection connection : moreResult.connections)
System.out.println(provider.getConnectionDetails(connection.link));
}
@Test
public void autoComplete() throws Exception
{
final List<Location> result = provider.autocompleteStations("haupt");
System.out.println(result);
}
}

View file

@ -16,9 +16,12 @@
*/
package de.schildbach.pte.live;
import java.util.List;
import org.junit.Test;
import de.schildbach.pte.SncbProvider;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.NearbyStationsResult;
/**
@ -28,6 +31,22 @@ public class SncbProviderLiveTest
{
private final SncbProvider provider = new SncbProvider();
@Test
public void autocompleteIncomplete() throws Exception
{
final List<Location> autocompletes = provider.autocompleteStations("Brussel S");
list(autocompletes);
}
private void list(final List<Location> autocompletes)
{
System.out.print(autocompletes.size() + " ");
for (final Location autocomplete : autocompletes)
System.out.print(autocomplete.toDebugString() + " ");
System.out.println();
}
@Test
public void nearbyStation() throws Exception
{