mirror of
https://gitlab.com/oeffi/public-transport-enabler.git
synced 2025-07-07 20:18:50 +00:00
departures for Hannover
git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@208 0924bc21-9374-b0fa-ee44-9ff1593b38f0
This commit is contained in:
parent
75ac46e270
commit
f66cb36bb5
7 changed files with 716 additions and 131 deletions
7
pom.xml
7
pom.xml
|
@ -15,6 +15,13 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.sf.kxml</groupId>
|
||||
<artifactId>kxml2</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
|
|
@ -18,11 +18,20 @@
|
|||
package de.schildbach.pte;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
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.util.XmlPullUtil;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
|
@ -112,4 +121,78 @@ public abstract class AbstractEfaProvider implements NetworkProvider
|
|||
{
|
||||
return (double) value / 1000000;
|
||||
}
|
||||
|
||||
protected abstract String parseLine(String number, String symbol, String mot);
|
||||
|
||||
public QueryDeparturesResult queryDepartures(final String uri) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
final CharSequence page = ParserUtils.scrape(uri);
|
||||
// System.out.println(page);
|
||||
|
||||
final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
|
||||
final XmlPullParser pp = factory.newPullParser();
|
||||
pp.setInput(new StringReader(page.toString()));
|
||||
|
||||
XmlPullUtil.jumpToStartTag(pp, null, "odvNameElem");
|
||||
final int locationId = Integer.parseInt(pp.getAttributeValue(null, "stopID"));
|
||||
|
||||
final String location = pp.nextText();
|
||||
|
||||
final Calendar departureTime = new GregorianCalendar();
|
||||
final List<Departure> departures = new ArrayList<Departure>(8);
|
||||
|
||||
XmlPullUtil.jumpToStartTag(pp, null, "itdDepartureList");
|
||||
while (XmlPullUtil.jumpToStartTag(pp, null, "itdDeparture"))
|
||||
{
|
||||
if (Integer.parseInt(pp.getAttributeValue(null, "stopID")) == locationId)
|
||||
{
|
||||
String position = pp.getAttributeValue(null, "platform");
|
||||
if (position != null)
|
||||
position = "Gl. " + position;
|
||||
|
||||
departureTime.clear();
|
||||
XmlPullUtil.jumpToStartTag(pp, null, "itdDate");
|
||||
processItdDate(pp, departureTime);
|
||||
XmlPullUtil.jumpToStartTag(pp, null, "itdTime");
|
||||
processItdTime(pp, departureTime);
|
||||
XmlPullUtil.jumpToStartTag(pp, null, "itdServingLine");
|
||||
|
||||
final String line = parseLine(pp.getAttributeValue(null, "number"), pp.getAttributeValue(null, "symbol"), pp.getAttributeValue(
|
||||
null, "motType"));
|
||||
|
||||
final boolean isRealtime = pp.getAttributeValue(null, "realtime").equals("1");
|
||||
|
||||
final String destination = pp.getAttributeValue(null, "direction");
|
||||
|
||||
final int destinationId = Integer.parseInt(pp.getAttributeValue(null, "destID"));
|
||||
|
||||
departures.add(new Departure(!isRealtime ? departureTime.getTime() : null, isRealtime ? departureTime.getTime() : null, line,
|
||||
lineColors(line), null, position, destinationId, destination, null));
|
||||
}
|
||||
}
|
||||
|
||||
return new QueryDeparturesResult(uri, locationId, location, departures);
|
||||
}
|
||||
catch (final XmlPullParserException x)
|
||||
{
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void processItdDate(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.require(XmlPullParser.START_TAG, null, "itdDate");
|
||||
calendar.set(Calendar.YEAR, Integer.parseInt(pp.getAttributeValue(null, "year")));
|
||||
calendar.set(Calendar.MONTH, Integer.parseInt(pp.getAttributeValue(null, "month")) - 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(pp.getAttributeValue(null, "day")));
|
||||
}
|
||||
|
||||
private void processItdTime(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.require(XmlPullParser.START_TAG, null, "itdTime");
|
||||
calendar.set(Calendar.HOUR, Integer.parseInt(pp.getAttributeValue(null, "hour")));
|
||||
calendar.set(Calendar.MINUTE, Integer.parseInt(pp.getAttributeValue(null, "minute")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,27 @@ package de.schildbach.pte;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
public class GvhProvider extends AbstractEfaProvider
|
||||
{
|
||||
public static final String NETWORK_ID = "mobil.gvh.de";
|
||||
private static final String API_BASE = "http://mobil.gvh.de/mobile2/";
|
||||
|
||||
public boolean hasCapabilities(final Capability... capabilities)
|
||||
{
|
||||
for (final Capability capability : capabilities)
|
||||
if (capability == Capability.DEPARTURES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final String AUTOCOMPLETE_URI = API_BASE
|
||||
+ "XML_STOPFINDER_REQUEST?outputFormat=XML&coordOutputFormat=WGS84&name_sf=%s&type_sf=any";
|
||||
private static final String ENCODING = "ISO-8859-1";
|
||||
|
@ -52,24 +65,94 @@ public class GvhProvider extends AbstractEfaProvider
|
|||
return null;
|
||||
}
|
||||
|
||||
public StationLocationResult stationLocation(String stationId) throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String departuresQueryUri(String stationId, int maxDepartures)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
final StringBuilder uri = new StringBuilder();
|
||||
uri.append(API_BASE).append("XSLT_DM_REQUEST");
|
||||
uri.append("?outputFormat=XML");
|
||||
uri.append("&coordOutputFormat=WGS84");
|
||||
uri.append("&type_dm=stop");
|
||||
uri.append("&name_dm=").append(stationId);
|
||||
uri.append("&mode=direct");
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
private static final Pattern P_LINE_RE = Pattern.compile("RE\\d+");
|
||||
private static final Pattern P_LINE_RB = Pattern.compile("RB\\d+");
|
||||
|
||||
public boolean hasCapabilities(Capability... capabilities)
|
||||
@Override
|
||||
protected String parseLine(final String number, final String symbol, final String mot)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (!number.equals(symbol))
|
||||
throw new IllegalStateException("number " + number + ", symbol " + symbol);
|
||||
|
||||
public int[] lineColors(String line)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
int t = Integer.parseInt(mot);
|
||||
|
||||
if (t == 0)
|
||||
{
|
||||
final String[] parts = number.split(" ", 3);
|
||||
final String type = parts[0];
|
||||
final String num = parts.length >= 2 ? parts[1] : null;
|
||||
final String str = type + (num != null ? num : "");
|
||||
if (type.equals("EC")) // Eurocity
|
||||
return 'I' + str;
|
||||
if (type.equals("IC")) // Intercity
|
||||
return 'I' + str;
|
||||
if (type.equals("ICE")) // Intercity Express
|
||||
return 'I' + str;
|
||||
if (type.equals("THA")) // Thalys
|
||||
return 'I' + str;
|
||||
|
||||
if (type.equals("IR")) // Interregio
|
||||
return 'R' + str;
|
||||
if (type.equals("RE")) // Regional-Express
|
||||
return 'R' + str;
|
||||
if (P_LINE_RE.matcher(type).matches())
|
||||
return 'R' + str;
|
||||
if (type.equals("RB")) // Regionalbahn
|
||||
return 'R' + str;
|
||||
if (P_LINE_RB.matcher(type).matches())
|
||||
return 'R' + str;
|
||||
if (type.equals("R")) // Regionalzug
|
||||
return 'R' + str;
|
||||
if (type.equals("WFB")) // Westfalenbahn
|
||||
return 'R' + str;
|
||||
if (type.equals("NWB")) // NordWestBahn
|
||||
return 'R' + str;
|
||||
if (type.equals("ME")) // Metronom
|
||||
return 'R' + str;
|
||||
if (type.equals("ERB")) // eurobahn
|
||||
return 'R' + str;
|
||||
if (type.equals("CAN")) // cantus
|
||||
return 'R' + str;
|
||||
if (type.equals("HEX")) // Veolia Verkehr Sachsen-Anhalt
|
||||
return 'R' + str;
|
||||
if (type.equals("EB")) // Erfurter Bahn
|
||||
return 'R' + str;
|
||||
if (type.equals("MRB")) // Mittelrheinbahn
|
||||
return 'R' + str;
|
||||
if (type.equals("ABR")) // ABELLIO Rail NRW
|
||||
return 'R' + str;
|
||||
|
||||
throw new IllegalArgumentException("cannot normalize: " + number);
|
||||
}
|
||||
if (t == 1)
|
||||
return 'S' + number;
|
||||
if (t == 3 || t == 4)
|
||||
return 'T' + number;
|
||||
if (t == 5 || t == 6 || t == 7 || t == 10)
|
||||
return 'B' + number;
|
||||
if (t == 9)
|
||||
return 'F' + number;
|
||||
if (t == 11)
|
||||
return '?' + number;
|
||||
|
||||
throw new IllegalStateException("cannot normalize mot '" + mot + "' number '" + number + "'");
|
||||
}
|
||||
|
||||
public QueryConnectionsResult queryConnections(LocationType fromType, String from, LocationType viaType, String via, LocationType toType,
|
||||
|
@ -78,18 +161,32 @@ public class GvhProvider extends AbstractEfaProvider
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public QueryDeparturesResult queryDepartures(String queryUri) throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public QueryConnectionsResult queryMoreConnections(String uri) throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public StationLocationResult stationLocation(String stationId) throws IOException
|
||||
public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private static final Map<Character, int[]> LINES = new HashMap<Character, int[]>();
|
||||
|
||||
static
|
||||
{
|
||||
LINES.put('I', new int[] { Color.WHITE, Color.RED, Color.RED });
|
||||
LINES.put('R', new int[] { Color.GRAY, Color.WHITE });
|
||||
LINES.put('S', new int[] { Color.parseColor("#006e34"), Color.WHITE });
|
||||
LINES.put('U', new int[] { Color.parseColor("#003090"), Color.WHITE });
|
||||
LINES.put('T', new int[] { Color.parseColor("#cc0000"), Color.WHITE });
|
||||
LINES.put('B', new int[] { Color.parseColor("#993399"), Color.WHITE });
|
||||
LINES.put('F', new int[] { Color.BLUE, Color.WHITE });
|
||||
LINES.put('?', new int[] { Color.DKGRAY, Color.WHITE });
|
||||
}
|
||||
|
||||
public int[] lineColors(final String line)
|
||||
{
|
||||
return LINES.get(line.charAt(0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,9 @@
|
|||
package de.schildbach.pte;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
|
@ -109,113 +103,8 @@ public class LinzProvider extends AbstractEfaProvider
|
|||
return uri.toString();
|
||||
}
|
||||
|
||||
private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern.compile(".*?" //
|
||||
+ "(?:" //
|
||||
+ "<itdOdv type=\"stop\" usage=\"dm\">(.*?)</itdOdv>.*?" // head
|
||||
+ "(?:<itdDepartureList>(.*?)</itdDepartureList>.*?)?" // departures
|
||||
+ "|" //
|
||||
+ "(Server-Wartung).*?" // messages
|
||||
+ ")" //
|
||||
, Pattern.DOTALL);
|
||||
private static final Pattern P_DEPARTURES_HEAD_FINE = Pattern.compile(".*?" //
|
||||
+ "<odvNameElem .*? stopID=\"(\\d+)\" [^>]*>" // locationId
|
||||
+ "([^<]*).*?" // location
|
||||
, Pattern.DOTALL);
|
||||
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<itdDeparture (.*?)</itdDeparture>", Pattern.DOTALL);
|
||||
private static final Pattern P_DEPARTURES_FINE = Pattern.compile("" //
|
||||
+ "stopID=\"(\\d+)\" [^>]* area=\"(\\d+)\" platform=\"(\\d+)?\" platformName=\"\".*?" // locationId
|
||||
+ "<itdDate year=\"(\\d+)\" month=\"(\\d+)\" day=\"(\\d+)\" weekday=\"\\d+\"/>" // date
|
||||
+ "<itdTime hour=\"(\\d+)\" minute=\"(\\d+)\" ap=\"\"/>" // time
|
||||
+ ".*?" //
|
||||
+ "<itdServingLine [^>]* number=\"([^<]*)\" symbol=\"([^<]*)\" motType=\"(\\d+)\" " // line, symbol, type
|
||||
+ "realtime=\"(\\d+)\" " // realtime
|
||||
+ "direction=\"([^\"]*)\" destID=\"(\\d+)\"" // destination, destinationId
|
||||
+ ".*?" //
|
||||
, Pattern.DOTALL);
|
||||
|
||||
public QueryDeparturesResult queryDepartures(final String uri) throws IOException
|
||||
{
|
||||
final CharSequence page = ParserUtils.scrape(uri);
|
||||
|
||||
// parse page
|
||||
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
|
||||
if (mHeadCoarse.matches())
|
||||
{
|
||||
if (mHeadCoarse.group(3) != null)
|
||||
return new QueryDeparturesResult(uri, QueryDeparturesResult.Status.SERVICE_DOWN);
|
||||
|
||||
final String headerText = mHeadCoarse.group(1);
|
||||
final String departuresText = mHeadCoarse.group(2);
|
||||
|
||||
final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(headerText);
|
||||
if (mHeadFine.matches())
|
||||
{
|
||||
final int locationId = Integer.parseInt(mHeadFine.group(1));
|
||||
final String location = ParserUtils.resolveEntities(mHeadFine.group(2));
|
||||
final List<Departure> departures = new ArrayList<Departure>(8);
|
||||
|
||||
if (departuresText != null)
|
||||
{
|
||||
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(departuresText);
|
||||
while (mDepCoarse.find())
|
||||
{
|
||||
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(1));
|
||||
if (mDepFine.matches())
|
||||
{
|
||||
if (Integer.parseInt(mDepFine.group(1)) == locationId)
|
||||
{
|
||||
final String area = mDepFine.group(2); // FIXME not clear what this is
|
||||
|
||||
final String position = mDepFine.group(3) != null ? "Gl. " + mDepFine.group(3) : null;
|
||||
|
||||
final Date departureDate = parseDate(mDepFine.group(4), mDepFine.group(5), mDepFine.group(6), mDepFine.group(7),
|
||||
mDepFine.group(8));
|
||||
|
||||
final String line = parseLine(mDepFine.group(9), mDepFine.group(10), mDepFine.group(11));
|
||||
|
||||
final boolean isRealtime = mDepFine.group(12).equals("1");
|
||||
|
||||
final String destination = mDepFine.group(13);
|
||||
|
||||
final int destinationId = Integer.parseInt(mDepFine.group(14));
|
||||
|
||||
departures.add(new Departure(!isRealtime ? departureDate : null, isRealtime ? departureDate : null, line, LINES
|
||||
.get(line.charAt(0)), null, position, destinationId, destination, null));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(1) + "' on " + uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new QueryDeparturesResult(uri, locationId, location, departures);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("cannot parse '" + headerText + "' on " + uri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("cannot parse '" + page + "' on " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
private static Date parseDate(final String year, final String month, final String day, final String hour, final String minute)
|
||||
{
|
||||
final Calendar calendar = new GregorianCalendar();
|
||||
calendar.clear();
|
||||
calendar.set(Calendar.YEAR, Integer.parseInt(year));
|
||||
calendar.set(Calendar.MONTH, Integer.parseInt(month) - 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day));
|
||||
calendar.set(Calendar.HOUR, Integer.parseInt(hour));
|
||||
calendar.set(Calendar.MINUTE, Integer.parseInt(minute));
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
private String parseLine(final String number, final String symbol, final String mot)
|
||||
@Override
|
||||
protected String parseLine(final String number, final String symbol, final String mot)
|
||||
{
|
||||
if (!number.equals(symbol))
|
||||
throw new IllegalStateException("number " + number + ", symbol " + symbol);
|
||||
|
@ -229,7 +118,7 @@ public class LinzProvider extends AbstractEfaProvider
|
|||
if (t == 8)
|
||||
return 'C' + number;
|
||||
|
||||
throw new IllegalStateException("cannot normalize type '" + mot + "' line '" + number + "'");
|
||||
throw new IllegalStateException("cannot normalize mot '" + mot + "' number '" + number + "'");
|
||||
}
|
||||
|
||||
private static final Map<Character, int[]> LINES = new HashMap<Character, int[]>();
|
||||
|
|
367
src/de/schildbach/pte/util/XmlPullUtil.java
Normal file
367
src/de/schildbach/pte/util/XmlPullUtil.java
Normal file
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
* For license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/).
|
||||
* According to www.xmlpull.org, this code is in the public domain.
|
||||
*/
|
||||
|
||||
package de.schildbach.pte.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
/**
|
||||
* Handy functions that combines XmlPull API into higher level functionality.
|
||||
*
|
||||
* @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
|
||||
* @author Naresh Bhatia
|
||||
*/
|
||||
public class XmlPullUtil
|
||||
{
|
||||
public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
|
||||
private XmlPullUtil()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return value of attribute with given name and no namespace.
|
||||
*/
|
||||
public static String getAttributeValue(XmlPullParser pp, String name)
|
||||
{
|
||||
return pp.getAttributeValue(XmlPullParser.NO_NAMESPACE, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return PITarget from Processing Instruction (PI) as defined in XML 1.0 Section 2.6 Processing Instructions <code>[16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'</code>
|
||||
*/
|
||||
public static String getPITarget(XmlPullParser pp) throws IllegalStateException
|
||||
{
|
||||
int eventType;
|
||||
|
||||
try
|
||||
{
|
||||
eventType = pp.getEventType();
|
||||
}
|
||||
catch (XmlPullParserException ex)
|
||||
{
|
||||
// should never happen ...
|
||||
throw new IllegalStateException("could not determine parser state: " + ex + pp.getPositionDescription());
|
||||
}
|
||||
|
||||
if (eventType != XmlPullParser.PROCESSING_INSTRUCTION)
|
||||
throw new IllegalStateException("parser must be on processing instruction and not " + XmlPullParser.TYPES[eventType]
|
||||
+ pp.getPositionDescription());
|
||||
|
||||
final String PI = pp.getText();
|
||||
for (int i = 0; i < PI.length(); i++)
|
||||
{
|
||||
if (isS(PI.charAt(i)))
|
||||
{
|
||||
// assert i > 0
|
||||
return PI.substring(0, i);
|
||||
}
|
||||
}
|
||||
return PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return everything past PITarget and S from Processing Instruction (PI) as defined in XML 1.0 Section 2.6
|
||||
* Processing Instructions <code>[16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'</code>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE:</b> if there is no PI data it returns empty string.
|
||||
*/
|
||||
public static String getPIData(XmlPullParser pp) throws IllegalStateException
|
||||
{
|
||||
int eventType;
|
||||
try
|
||||
{
|
||||
eventType = pp.getEventType();
|
||||
}
|
||||
catch (XmlPullParserException ex)
|
||||
{
|
||||
// should never happen ...
|
||||
throw new IllegalStateException("could not determine parser state: " + ex + pp.getPositionDescription());
|
||||
}
|
||||
|
||||
if (eventType != XmlPullParser.PROCESSING_INSTRUCTION)
|
||||
throw new IllegalStateException("parser must be on processing instruction and not " + XmlPullParser.TYPES[eventType]
|
||||
+ pp.getPositionDescription());
|
||||
|
||||
final String PI = pp.getText();
|
||||
int pos = -1;
|
||||
for (int i = 0; i < PI.length(); i++)
|
||||
{
|
||||
if (isS(PI.charAt(i)))
|
||||
{
|
||||
pos = i;
|
||||
}
|
||||
else if (pos > 0)
|
||||
{
|
||||
return PI.substring(i);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if chacters is S as defined in XML 1.0 <code>S ::= (#x20 | #x9 | #xD | #xA)+</code>
|
||||
*/
|
||||
private static boolean isS(char ch)
|
||||
{
|
||||
return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip sub tree that is currently porser positioned on. <br>
|
||||
* NOTE: parser must be on START_TAG and when funtion returns parser will be positioned on corresponding END_TAG
|
||||
*/
|
||||
public static void skipSubTree(XmlPullParser pp) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.require(XmlPullParser.START_TAG, null, null);
|
||||
|
||||
int level = 1;
|
||||
while (level > 0)
|
||||
{
|
||||
int eventType = pp.next();
|
||||
if (eventType == XmlPullParser.END_TAG)
|
||||
--level;
|
||||
else if (eventType == XmlPullParser.START_TAG)
|
||||
++level;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call parser nextTag() and check that it is START_TAG, throw exception if not.
|
||||
*/
|
||||
public static void nextStartTag(XmlPullParser pp) throws XmlPullParserException, IOException
|
||||
{
|
||||
if (pp.nextTag() != XmlPullParser.START_TAG)
|
||||
throw new XmlPullParserException("expected START_TAG and not " + pp.getPositionDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
* combine nextTag(); pp.require(XmlPullParser.START_TAG, null, name);
|
||||
*/
|
||||
public static void nextStartTag(XmlPullParser pp, String name) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.nextTag();
|
||||
pp.require(XmlPullParser.START_TAG, null, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* combine nextTag(); pp.require(XmlPullParser.START_TAG, namespace, name);
|
||||
*/
|
||||
public static void nextStartTag(XmlPullParser pp, String namespace, String name) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.nextTag();
|
||||
pp.require(XmlPullParser.START_TAG, namespace, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* combine nextTag(); pp.require(XmlPullParser.END_TAG, namespace, name);
|
||||
*/
|
||||
public static void nextEndTag(XmlPullParser pp, String namespace, String name) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.nextTag();
|
||||
pp.require(XmlPullParser.END_TAG, namespace, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read text content of element ith given namespace and name (use null namespace do indicate that nemspace should
|
||||
* not be checked)
|
||||
*/
|
||||
|
||||
public static String nextText(XmlPullParser pp, String namespace, String name) throws IOException, XmlPullParserException
|
||||
{
|
||||
if (name == null)
|
||||
throw new XmlPullParserException("name for element can not be null");
|
||||
|
||||
pp.require(XmlPullParser.START_TAG, namespace, name);
|
||||
return pp.nextText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read attribute value and return it or throw exception if current element does not have such attribute.
|
||||
*/
|
||||
|
||||
public static String getRequiredAttributeValue(XmlPullParser pp, String namespace, String name) throws IOException, XmlPullParserException
|
||||
{
|
||||
final String value = pp.getAttributeValue(namespace, name);
|
||||
if (value == null)
|
||||
throw new XmlPullParserException("required attribute " + name + " is not present");
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call parser nextTag() and check that it is END_TAG, throw exception if not.
|
||||
*/
|
||||
public static void nextEndTag(XmlPullParser pp) throws XmlPullParserException, IOException
|
||||
{
|
||||
if (pp.nextTag() != XmlPullParser.END_TAG)
|
||||
throw new XmlPullParserException("expected END_TAG and not" + pp.getPositionDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the current event is of the given type and if the namespace and name match. null will match any
|
||||
* namespace and any name. If the test passes a true is returned otherwise a false is returned.
|
||||
*/
|
||||
public static boolean matches(XmlPullParser pp, int type, String namespace, String name) throws XmlPullParserException
|
||||
{
|
||||
boolean matches = type == pp.getEventType() && (namespace == null || namespace.equals(pp.getNamespace()))
|
||||
&& (name == null || name.equals(pp.getName()));
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a simple element such as <username>johndoe</username>. The namespace and elementText are allowed to be
|
||||
* null. If elementText is null, an xsi:nil="true" will be added as an attribute.
|
||||
*/
|
||||
public static void writeSimpleElement(XmlSerializer serializer, String namespace, String elementName, String elementText) throws IOException,
|
||||
XmlPullParserException
|
||||
{
|
||||
if (elementName == null)
|
||||
throw new XmlPullParserException("name for element can not be null");
|
||||
|
||||
serializer.startTag(namespace, elementName);
|
||||
if (elementText == null)
|
||||
{
|
||||
serializer.attribute(XSI_NS, "nil", "true");
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer.text(elementText);
|
||||
}
|
||||
serializer.endTag(namespace, elementName);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method bypasses all child subtrees until it reached END_TAG for current tree. Parser must be on START_TAG of
|
||||
* one of child subtrees.
|
||||
*/
|
||||
public static void jumpToEndOfTree(final XmlPullParser pp) throws XmlPullParserException, IOException
|
||||
{
|
||||
pp.require(XmlPullParser.START_TAG, null, null);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int eventType = pp.next();
|
||||
if (eventType == XmlPullParser.START_TAG)
|
||||
{
|
||||
skipSubTree(pp);
|
||||
pp.require(XmlPullParser.END_TAG, null, null);
|
||||
pp.next(); // skip end tag
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method bypasses all child subtrees until it finds a child subtree with start tag that matches the tag name
|
||||
* (if not null) and namespsce (if not null) passed in. Parser must be positioned on START_TAG.
|
||||
* <p>
|
||||
* If succesfulpositions parser on such START_TAG and return true otherwise this method returns false and parser is
|
||||
* positioned on END_TAG signaling last element in curren subtree.
|
||||
*/
|
||||
public static boolean jumpToSubTree(final XmlPullParser pp, final String tagNamespace, final String tagName) throws XmlPullParserException,
|
||||
IOException
|
||||
{
|
||||
if (tagNamespace == null && tagName == null)
|
||||
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
|
||||
|
||||
pp.require(XmlPullParser.START_TAG, null, null);
|
||||
while (true)
|
||||
{
|
||||
int eventType = pp.next();
|
||||
|
||||
if (eventType == XmlPullParser.START_TAG)
|
||||
{
|
||||
String name = pp.getName();
|
||||
String namespace = pp.getNamespace();
|
||||
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
|
||||
if (matches)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
skipSubTree(pp);
|
||||
pp.require(XmlPullParser.END_TAG, name, namespace);
|
||||
pp.next(); // skip end tag
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method bypasses all events until it finds a start tag that has passed in namespace (if not null) and
|
||||
* namespace (if not null).
|
||||
*
|
||||
* @return true if such START_TAG was found or false otherwise (and parser is on END_DOCUMENT).
|
||||
*/
|
||||
public static boolean jumpToStartTag(final XmlPullParser pp, final String tagNamespace, final String tagName) throws XmlPullParserException,
|
||||
IOException
|
||||
{
|
||||
if (tagNamespace == null && tagName == null)
|
||||
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
|
||||
|
||||
while (true)
|
||||
{
|
||||
int eventType = pp.next();
|
||||
if (eventType == XmlPullParser.START_TAG)
|
||||
{
|
||||
String name = pp.getName();
|
||||
String namespace = pp.getNamespace();
|
||||
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
|
||||
if (matches)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_DOCUMENT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method bypasses all events until it finds an end tag that has passed in namespace (if not null) and
|
||||
* namespace (if not null).
|
||||
*
|
||||
* @return true if such END_TAG was found or false otherwise (and parser is on END_DOCUMENT).
|
||||
*/
|
||||
public static boolean jumpToEndTag(final XmlPullParser pp, final String tagNamespace, final String tagName) throws XmlPullParserException,
|
||||
IOException
|
||||
{
|
||||
if (tagNamespace == null && tagName == null)
|
||||
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
|
||||
|
||||
while (true)
|
||||
{
|
||||
int eventType = pp.next();
|
||||
if (eventType == XmlPullParser.END_TAG)
|
||||
{
|
||||
String name = pp.getName();
|
||||
String namespace = pp.getNamespace();
|
||||
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
|
||||
if (matches)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_DOCUMENT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
test/de/schildbach/pte/live/GvhProviderLiveTest.java
Normal file
49
test/de/schildbach/pte/live/GvhProviderLiveTest.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import de.schildbach.pte.Autocomplete;
|
||||
import de.schildbach.pte.GvhProvider;
|
||||
import de.schildbach.pte.Station;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
public class GvhProviderLiveTest
|
||||
{
|
||||
private final GvhProvider provider = new GvhProvider();
|
||||
|
||||
@Test
|
||||
public void autocomplete() throws Exception
|
||||
{
|
||||
final List<Autocomplete> results = provider.autocompleteStations("Hannover");
|
||||
|
||||
System.out.println(results.size() + " " + results);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearby() throws Exception
|
||||
{
|
||||
final List<Station> results = provider.nearbyStations("25000031", 0, 0, 0, 0);
|
||||
|
||||
System.out.println(results.size() + " " + results);
|
||||
}
|
||||
}
|
93
test/de/schildbach/pte/live/LinzProviderLiveTest.java
Normal file
93
test/de/schildbach/pte/live/LinzProviderLiveTest.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import de.schildbach.pte.LinzProvider;
|
||||
import de.schildbach.pte.QueryConnectionsResult;
|
||||
import de.schildbach.pte.QueryDeparturesResult;
|
||||
import de.schildbach.pte.NetworkProvider.LocationType;
|
||||
import de.schildbach.pte.NetworkProvider.WalkSpeed;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
public class LinzProviderLiveTest
|
||||
{
|
||||
private LinzProvider provider = new LinzProvider();
|
||||
|
||||
@Test
|
||||
public void queryDepartures() throws Exception
|
||||
{
|
||||
final QueryDeparturesResult result = provider.queryDepartures(provider.departuresQueryUri("60501720", 0));
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shortConnection() throws Exception
|
||||
{
|
||||
final QueryConnectionsResult result = provider.queryConnections(LocationType.STATION, "Linz Hauptbahnhof", null, null, LocationType.STATION,
|
||||
"Linz Auwiesen", new Date(), true, WalkSpeed.FAST);
|
||||
System.out.println(result);
|
||||
// final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater);
|
||||
// System.out.println(moreResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longConnection() throws Exception
|
||||
{
|
||||
final QueryConnectionsResult result = provider.queryConnections(LocationType.STATION, "Linz Auwiesen", null, null, LocationType.STATION,
|
||||
"Linz Hafen", new Date(), true, WalkSpeed.SLOW);
|
||||
System.out.println(result);
|
||||
// final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater);
|
||||
// System.out.println(moreResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionBetweenCoordinates() throws Exception
|
||||
{
|
||||
final QueryConnectionsResult result = provider.queryConnections(LocationType.WGS84, "48.165238,11.577473", null, null, LocationType.WGS84,
|
||||
"47.987199,11.326532", new Date(), true, WalkSpeed.NORMAL);
|
||||
System.out.println(result);
|
||||
// final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater);
|
||||
// System.out.println(moreResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionBetweenCoordinateAndStation() throws Exception
|
||||
{
|
||||
final QueryConnectionsResult result = provider.queryConnections(LocationType.WGS84, "48.238341,11.478230", null, null, LocationType.ANY,
|
||||
"Ostbahnhof", new Date(), true, WalkSpeed.NORMAL);
|
||||
System.out.println(result);
|
||||
// final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater);
|
||||
// System.out.println(moreResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionBetweenAddresses() throws Exception
|
||||
{
|
||||
final QueryConnectionsResult result = provider.queryConnections(LocationType.ADDRESS, "München, Maximilianstr. 1", null, null,
|
||||
LocationType.ADDRESS, "Starnberg, Jahnstraße 50", new Date(), true, WalkSpeed.NORMAL);
|
||||
System.out.println(result);
|
||||
// final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater);
|
||||
// System.out.println(moreResult);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue