From 8f85e8ce86f3df16c498987d6d69259d8b64bd50 Mon Sep 17 00:00:00 2001 From: "andreas.schildbach" Date: Sat, 25 Sep 2010 19:37:37 +0000 Subject: [PATCH] auto-complete addresses for Austria git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@200 0924bc21-9374-b0fa-ee44-9ff1593b38f0 --- src/de/schildbach/pte/Autocomplete.java | 6 +- src/de/schildbach/pte/BahnProvider.java | 4 +- src/de/schildbach/pte/LinzProvider.java | 4 +- src/de/schildbach/pte/MvvProvider.java | 2 +- src/de/schildbach/pte/OebbProvider.java | 78 +++++++++++++++---- src/de/schildbach/pte/RmvProvider.java | 4 +- src/de/schildbach/pte/SbbProvider.java | 4 +- src/de/schildbach/pte/VbbProvider.java | 7 +- .../pte/live/SbbProviderLiveTest.java | 9 +++ 9 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/de/schildbach/pte/Autocomplete.java b/src/de/schildbach/pte/Autocomplete.java index 13ab98c3..ef7bda39 100644 --- a/src/de/schildbach/pte/Autocomplete.java +++ b/src/de/schildbach/pte/Autocomplete.java @@ -16,16 +16,20 @@ */ package de.schildbach.pte; +import de.schildbach.pte.NetworkProvider.LocationType; + /** * @author Andreas Schildbach */ public final class Autocomplete { + public final LocationType locationType; public final int locationId; public final String location; - public Autocomplete(final int locationId, final String location) + public Autocomplete(final LocationType locationType, final int locationId, final String location) { + this.locationType = locationType; this.locationId = locationId; this.location = location; } diff --git a/src/de/schildbach/pte/BahnProvider.java b/src/de/schildbach/pte/BahnProvider.java index 1f23c02e..479a4a62 100644 --- a/src/de/schildbach/pte/BahnProvider.java +++ b/src/de/schildbach/pte/BahnProvider.java @@ -64,13 +64,13 @@ public final class BahnProvider implements NetworkProvider final Matcher mSingle = P_SINGLE_NAME.matcher(page); if (mSingle.matches()) { - results.add(new Autocomplete(Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); } else { final Matcher mMulti = P_MULTI_NAME.matcher(page); while (mMulti.find()) - results.add(new Autocomplete(Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); } return results; diff --git a/src/de/schildbach/pte/LinzProvider.java b/src/de/schildbach/pte/LinzProvider.java index 6a120e69..07f710c2 100644 --- a/src/de/schildbach/pte/LinzProvider.java +++ b/src/de/schildbach/pte/LinzProvider.java @@ -72,12 +72,12 @@ public class LinzProvider implements NetworkProvider // final double sLon = latLonToDouble(Integer.parseInt(mAutocomplete.group(2))); // final double sLat = latLonToDouble(Integer.parseInt(mAutocomplete.group(3))); final String sName = m.group(4).trim(); - results.add(new Autocomplete(sId, sName)); + results.add(new Autocomplete(LocationType.STATION, sId, sName)); } else if (m.group(5) != null) { final String sName = m.group(5).trim(); - results.add(new Autocomplete(0, sName)); + results.add(new Autocomplete(LocationType.ANY, 0, sName)); } } diff --git a/src/de/schildbach/pte/MvvProvider.java b/src/de/schildbach/pte/MvvProvider.java index 6314960d..632f53db 100644 --- a/src/de/schildbach/pte/MvvProvider.java +++ b/src/de/schildbach/pte/MvvProvider.java @@ -78,7 +78,7 @@ public class MvvProvider implements NetworkProvider if (type.equals("stop")) { - final Autocomplete result = new Autocomplete(locationId, city + ", " + location); + final Autocomplete result = new Autocomplete(LocationType.STATION, locationId, city + ", " + location); results.add(result); } } diff --git a/src/de/schildbach/pte/OebbProvider.java b/src/de/schildbach/pte/OebbProvider.java index bc871944..61b4b84a 100644 --- a/src/de/schildbach/pte/OebbProvider.java +++ b/src/de/schildbach/pte/OebbProvider.java @@ -20,6 +20,7 @@ import de.schildbach.pte.QueryDeparturesResult.Status; public class OebbProvider implements NetworkProvider { public static final String NETWORK_ID = "fahrplan.oebb.at"; + public static final String API_BASE = "http://fahrplan.oebb.at/bin/"; public boolean hasCapabilities(final Capability... capabilities) { @@ -30,30 +31,77 @@ public class OebbProvider implements NetworkProvider return false; } - private static final String NAME_URL = "http://fahrplan.oebb.at/bin/stboard.exe/dn?input="; - private static final Pattern P_SINGLE_NAME = Pattern - .compile(".*?.*", Pattern.DOTALL); - private static final Pattern P_MULTI_NAME = Pattern.compile("", Pattern.DOTALL); + private static final String AUTOCOMPLETE_URI = API_BASE + + "ajax-getstop.exe/dny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=255&REQ0JourneyStopsB=12&S=%s?&js=true&"; + private static final String ENCODING = "ISO-8859-1"; + 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+)@.*?"); public List autocompleteStations(final CharSequence constraint) throws IOException { - final CharSequence page = ParserUtils.scrape(NAME_URL + ParserUtils.urlEncode(constraint.toString())); + final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING)); + final CharSequence page = ParserUtils.scrape(uri); - final List results = new ArrayList(); - - final Matcher mSingle = P_SINGLE_NAME.matcher(page); - if (mSingle.matches()) + final Matcher mJson = P_AUTOCOMPLETE_JSON.matcher(page); + if (mJson.matches()) { - results.add(new Autocomplete(Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); + final String json = mJson.group(1); + final List results = new ArrayList(); + + try + { + final JSONObject head = new JSONObject(json); + final JSONArray aSuggestions = head.getJSONArray("suggestions"); + + for (int i = 0; i < aSuggestions.length(); i++) + { + final JSONObject suggestion = aSuggestions.optJSONObject(i); + if (suggestion != null) + { + final int type = suggestion.getInt("type"); + final String value = suggestion.getString("value"); + + if (type == 1) // station + { + final String id = suggestion.getString("id"); + final Matcher m = P_AUTOCOMPLETE_ID.matcher(id); + if (m.matches()) + { + final int localId = Integer.parseInt(m.group(1)); + results.add(new Autocomplete(LocationType.STATION, localId, value)); + } + else + { + throw new IllegalStateException("id does not match: " + id); + } + } + else if (type == 2) // address + { + results.add(new Autocomplete(LocationType.ADDRESS, 0, value)); + } + else if (type == 4) // poi + { + results.add(new Autocomplete(LocationType.ANY, 0, value)); + } + else + { + throw new IllegalStateException("unknown type " + type + " on " + uri); + } + } + } + + return results; + } + catch (final JSONException x) + { + x.printStackTrace(); + throw new RuntimeException("cannot parse: '" + json + "' on " + uri, x); + } } else { - final Matcher mMulti = P_MULTI_NAME.matcher(page); - while (mMulti.find()) - results.add(new Autocomplete(Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); + throw new RuntimeException("cannot parse: '" + page + "' on " + uri); } - - return results; } private final String NEARBY_URI = "http://fahrplan.oebb.at/bin/stboard.exe/dn?distance=50&near=Suchen&input=%d"; diff --git a/src/de/schildbach/pte/RmvProvider.java b/src/de/schildbach/pte/RmvProvider.java index b6f4155a..fa83081c 100644 --- a/src/de/schildbach/pte/RmvProvider.java +++ b/src/de/schildbach/pte/RmvProvider.java @@ -66,13 +66,13 @@ public class RmvProvider implements NetworkProvider final Matcher mSingle = P_SINGLE_NAME.matcher(page); if (mSingle.matches()) { - results.add(new Autocomplete(Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); } else { final Matcher mMulti = P_MULTI_NAME.matcher(page); while (mMulti.find()) - results.add(new Autocomplete(Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); } return results; diff --git a/src/de/schildbach/pte/SbbProvider.java b/src/de/schildbach/pte/SbbProvider.java index e23d736a..13f5d025 100644 --- a/src/de/schildbach/pte/SbbProvider.java +++ b/src/de/schildbach/pte/SbbProvider.java @@ -66,13 +66,13 @@ public class SbbProvider implements NetworkProvider final Matcher mSingle = P_SINGLE_NAME.matcher(page); if (mSingle.matches()) { - results.add(new Autocomplete(Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mSingle.group(2)), ParserUtils.resolveEntities(mSingle.group(1)))); } else { final Matcher mMulti = P_MULTI_NAME.matcher(page); while (mMulti.find()) - results.add(new Autocomplete(Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); } return results; diff --git a/src/de/schildbach/pte/VbbProvider.java b/src/de/schildbach/pte/VbbProvider.java index 853693a7..c119f357 100644 --- a/src/de/schildbach/pte/VbbProvider.java +++ b/src/de/schildbach/pte/VbbProvider.java @@ -73,7 +73,7 @@ public final class VbbProvider implements NetworkProvider final Matcher mSingle = P_SINGLE_MASTID.matcher(page); if (mSingle.matches()) { - results.add(new Autocomplete(0 /* TODO */, ParserUtils.resolveEntities(mSingle.group(1)))); + results.add(new Autocomplete(LocationType.ANY, 0 /* TODO */, ParserUtils.resolveEntities(mSingle.group(1)))); } } else @@ -83,13 +83,14 @@ public final class VbbProvider implements NetworkProvider final Matcher mSingle = P_SINGLE_NAME.matcher(page); if (mSingle.matches()) { - results.add(new Autocomplete(0 /* TODO */, ParserUtils.resolveEntities(mSingle.group(1)))); + results.add(new Autocomplete(LocationType.ANY, 0 /* TODO */, ParserUtils.resolveEntities(mSingle.group(1)))); } else { final Matcher mMulti = P_MULTI_NAME.matcher(page); while (mMulti.find()) - results.add(new Autocomplete(Integer.parseInt(mMulti.group(1)), ParserUtils.resolveEntities(mMulti.group(2)))); + results.add(new Autocomplete(LocationType.STATION, Integer.parseInt(mMulti.group(1)), ParserUtils + .resolveEntities(mMulti.group(2)))); } } diff --git a/test/de/schildbach/pte/live/SbbProviderLiveTest.java b/test/de/schildbach/pte/live/SbbProviderLiveTest.java index 9a1375c5..19e56c99 100644 --- a/test/de/schildbach/pte/live/SbbProviderLiveTest.java +++ b/test/de/schildbach/pte/live/SbbProviderLiveTest.java @@ -18,9 +18,11 @@ package de.schildbach.pte.live; import java.util.Date; +import java.util.List; import org.junit.Test; +import de.schildbach.pte.Autocomplete; import de.schildbach.pte.QueryConnectionsResult; import de.schildbach.pte.SbbProvider; import de.schildbach.pte.NetworkProvider.LocationType; @@ -62,4 +64,11 @@ public class SbbProviderLiveTest final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater); System.out.println(moreResult); } + + @Test + public void autoComplete() throws Exception + { + final List result = provider.autocompleteStations("haupt"); + System.out.println(result); + } }