diff --git a/src/de/schildbach/pte/AbstractEfaProvider.java b/src/de/schildbach/pte/AbstractEfaProvider.java index 9d2275dc..916f1b3d 100644 --- a/src/de/schildbach/pte/AbstractEfaProvider.java +++ b/src/de/schildbach/pte/AbstractEfaProvider.java @@ -47,6 +47,7 @@ import de.schildbach.pte.dto.NearbyStationsResult; import de.schildbach.pte.dto.QueryConnectionsResult; import de.schildbach.pte.dto.QueryDeparturesResult; import de.schildbach.pte.dto.Station; +import de.schildbach.pte.dto.Stop; import de.schildbach.pte.dto.QueryConnectionsResult.Status; import de.schildbach.pte.util.Color; import de.schildbach.pte.util.ParserUtils; @@ -694,7 +695,7 @@ public abstract class AbstractEfaProvider implements NetworkProvider XmlPullUtil.jumpToStartTag(pp, null, "itdServingLines"); if (!pp.isEmptyElementTag()) { - XmlPullUtil.enter(pp); + XmlPullUtil.enter(pp, "itdServingLines"); while (XmlPullUtil.test(pp, "itdServingLine")) { try @@ -716,7 +717,7 @@ public abstract class AbstractEfaProvider implements NetworkProvider XmlPullUtil.enter(pp); XmlPullUtil.exit(pp); } - XmlPullUtil.exit(pp); + XmlPullUtil.exit(pp, "itdServingLines"); } else { @@ -726,30 +727,44 @@ public abstract class AbstractEfaProvider implements NetworkProvider final List departures = new ArrayList(8); XmlPullUtil.require(pp, "itdDepartureList"); - while (XmlPullUtil.nextStartTagInsideTree(pp, null, "itdDeparture")) + if (!pp.isEmptyElementTag()) { - if (Integer.parseInt(pp.getAttributeValue(null, "stopID")) == locationId) + XmlPullUtil.enter(pp, "itdDepartureList"); + while (XmlPullUtil.test(pp, "itdDeparture")) { - final String position = normalizePlatform(pp.getAttributeValue(null, "platform"), pp.getAttributeValue(null, "platformName")); + if (Integer.parseInt(pp.getAttributeValue(null, "stopID")) == locationId) + { + final String position = normalizePlatform(pp.getAttributeValue(null, "platform"), pp.getAttributeValue(null, + "platformName")); - departureTime.clear(); + XmlPullUtil.enter(pp, "itdDeparture"); - processItdDateTime(pp, departureTime); + departureTime.clear(); + processItdDateTime(pp, departureTime); - if (!XmlPullUtil.nextStartTagInsideTree(pp, null, "itdServingLine")) - throw new IllegalStateException("itdServingLine not found:" + pp.getPositionDescription()); - final String line = parseLine(pp.getAttributeValue(null, "motType"), pp.getAttributeValue(null, "number"), pp - .getAttributeValue(null, "number")); - final boolean isRealtime = pp.getAttributeValue(null, "realtime").equals("1"); - final String destination = normalizeLocationName(pp.getAttributeValue(null, "direction")); - final int destinationId = Integer.parseInt(pp.getAttributeValue(null, "destID")); - XmlPullUtil.skipRestOfTree(pp); + // TODO + if (XmlPullUtil.test(pp, "itdRTDateTime")) + XmlPullUtil.next(pp); - departures.add(new Departure(!isRealtime ? departureTime.getTime() : null, isRealtime ? departureTime.getTime() : null, line, - lineColors(line), null, position, destinationId, destination, null)); + XmlPullUtil.require(pp, "itdServingLine"); + final String line = parseLine(pp.getAttributeValue(null, "motType"), pp.getAttributeValue(null, "number"), pp + .getAttributeValue(null, "number")); + final boolean isRealtime = pp.getAttributeValue(null, "realtime").equals("1"); + final String destination = normalizeLocationName(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)); + } + else + { + XmlPullUtil.enter(pp, "itdDeparture"); + } + + XmlPullUtil.exit(pp, "itdDeparture"); } - XmlPullUtil.skipRestOfTree(pp); + XmlPullUtil.exit(pp, "itdDepartureList"); } return new QueryDeparturesResult(new Location(LocationType.STATION, locationId, 0, 0, location), departures, lines); @@ -782,37 +797,37 @@ public abstract class AbstractEfaProvider implements NetworkProvider } } - private void processItdDateTime(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException + private void findAndProcessItdDateTime(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException { if (!XmlPullUtil.nextStartTagInsideTree(pp, null, "itdDateTime")) throw new IllegalStateException("itdDateTime not found:" + pp.getPositionDescription()); - if (!XmlPullUtil.nextStartTagInsideTree(pp, null, "itdDate")) - throw new IllegalStateException("itdDate not found:" + pp.getPositionDescription()); + processItdDateTime(pp, calendar); + } + + private void processItdDateTime(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException + { + XmlPullUtil.enter(pp, "itdDateTime"); processItdDate(pp, calendar); - XmlPullUtil.skipRestOfTree(pp); - - if (!XmlPullUtil.nextStartTagInsideTree(pp, null, "itdTime")) - throw new IllegalStateException("itdTime not found:" + pp.getPositionDescription()); processItdTime(pp, calendar); - XmlPullUtil.skipRestOfTree(pp); - - XmlPullUtil.skipRestOfTree(pp); + XmlPullUtil.exit(pp, "itdDateTime"); } private void processItdDate(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException { - pp.require(XmlPullParser.START_TAG, null, "itdDate"); + XmlPullUtil.require(pp, "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"))); + XmlPullUtil.next(pp); } private void processItdTime(final XmlPullParser pp, final Calendar calendar) throws XmlPullParserException, IOException { - pp.require(XmlPullParser.START_TAG, null, "itdTime"); + XmlPullUtil.require(pp, "itdTime"); calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(pp.getAttributeValue(null, "hour"))); calendar.set(Calendar.MINUTE, Integer.parseInt(pp.getAttributeValue(null, "minute"))); + XmlPullUtil.next(pp); } private static final Pattern P_STATION_NAME_WHITESPACE = Pattern.compile("\\s+"); @@ -955,27 +970,35 @@ public abstract class AbstractEfaProvider implements NetworkProvider return new QueryConnectionsResult(Status.INVALID_DATE); } - final Calendar departureTime = new GregorianCalendar(), arrivalTime = new GregorianCalendar(); + final Calendar departureTime = new GregorianCalendar(), arrivalTime = new GregorianCalendar(), stopTime = new GregorianCalendar(); departureTime.setTimeZone(timeZone()); arrivalTime.setTimeZone(timeZone()); final List connections = new ArrayList(); if (XmlPullUtil.jumpToStartTag(pp, null, "itdRouteList")) { - while (XmlPullUtil.nextStartTagInsideTree(pp, null, "itdRoute")) + XmlPullUtil.enter(pp, "itdRouteList"); + + while (XmlPullUtil.test(pp, "itdRoute")) { final String id = pp.getAttributeValue(null, "routeIndex") + "-" + pp.getAttributeValue(null, "routeTripIndex"); + XmlPullUtil.enter(pp, "itdRoute"); - XmlPullUtil.jumpToStartTag(pp, null, "itdPartialRouteList"); + if (XmlPullUtil.test(pp, "itdMapItemList")) + XmlPullUtil.next(pp); + + XmlPullUtil.enter(pp, "itdPartialRouteList"); final List parts = new LinkedList(); String firstDeparture = null; Date firstDepartureTime = null; String lastArrival = null; Date lastArrivalTime = null; - while (XmlPullUtil.nextStartTagInsideTree(pp, null, "itdPartialRoute")) + while (XmlPullUtil.test(pp, "itdPartialRoute")) { - XmlPullUtil.jumpToStartTag(pp, null, "itdPoint"); + XmlPullUtil.enter(pp, "itdPartialRoute"); + + XmlPullUtil.test(pp, "itdPoint"); if (!"departure".equals(pp.getAttributeValue(null, "usage"))) throw new IllegalStateException(); final int departureId = Integer.parseInt(pp.getAttributeValue(null, "stopID")); @@ -984,12 +1007,15 @@ public abstract class AbstractEfaProvider implements NetworkProvider firstDeparture = departure; final String departurePosition = normalizePlatform(pp.getAttributeValue(null, "platform"), pp.getAttributeValue(null, "platformName")); + XmlPullUtil.enter(pp, "itdPoint"); + if (XmlPullUtil.test(pp, "itdMapItemList")) + XmlPullUtil.next(pp); processItdDateTime(pp, departureTime); if (firstDepartureTime == null) firstDepartureTime = departureTime.getTime(); - XmlPullUtil.skipRestOfTree(pp); + XmlPullUtil.exit(pp, "itdPoint"); - XmlPullUtil.jumpToStartTag(pp, null, "itdPoint"); + XmlPullUtil.test(pp, "itdPoint"); if (!"arrival".equals(pp.getAttributeValue(null, "usage"))) throw new IllegalStateException(); final int arrivalId = Integer.parseInt(pp.getAttributeValue(null, "stopID")); @@ -997,11 +1023,14 @@ public abstract class AbstractEfaProvider implements NetworkProvider lastArrival = arrival; final String arrivalPosition = normalizePlatform(pp.getAttributeValue(null, "platform"), pp.getAttributeValue(null, "platformName")); + XmlPullUtil.enter(pp, "itdPoint"); + if (XmlPullUtil.test(pp, "itdMapItemList")) + XmlPullUtil.next(pp); processItdDateTime(pp, arrivalTime); lastArrivalTime = arrivalTime.getTime(); - XmlPullUtil.skipRestOfTree(pp); + XmlPullUtil.exit(pp, "itdPoint"); - XmlPullUtil.jumpToStartTag(pp, null, "itdMeansOfTransport"); + XmlPullUtil.test(pp, "itdMeansOfTransport"); final String productName = pp.getAttributeValue(null, "productName"); if ("Fussweg".equals(productName)) // type99 { @@ -1017,10 +1046,16 @@ public abstract class AbstractEfaProvider implements NetworkProvider { parts.add(new Connection.Footway(min, departureId, departure, arrivalId, arrival)); } + + XmlPullUtil.enter(pp, "itdMeansOfTransport"); + XmlPullUtil.exit(pp, "itdMeansOfTransport"); } else if ("gesicherter Anschluss".equals(productName) || "nicht umsteigen".equals(productName)) // type97 { // ignore + + XmlPullUtil.enter(pp, "itdMeansOfTransport"); + XmlPullUtil.exit(pp, "itdMeansOfTransport"); } else { @@ -1029,19 +1064,60 @@ public abstract class AbstractEfaProvider implements NetworkProvider final String destination = normalizeLocationName(pp.getAttributeValue(null, "destination")); final String line = parseLine(pp.getAttributeValue(null, "motType"), pp.getAttributeValue(null, "shortname"), pp .getAttributeValue(null, "name")); - parts.add(new Connection.Trip(line, lineColors(line), destinationId, destination, departureTime.getTime(), - departurePosition, departureId, departure, arrivalTime.getTime(), arrivalPosition, arrivalId, arrival)); - } - XmlPullUtil.skipRestOfTree(pp); - XmlPullUtil.skipRestOfTree(pp); + XmlPullUtil.enter(pp, "itdMeansOfTransport"); + XmlPullUtil.exit(pp, "itdMeansOfTransport"); + + if (XmlPullUtil.test(pp, "itdRBLControlled")) + XmlPullUtil.next(pp); + if (XmlPullUtil.test(pp, "itdInfoTextList")) + XmlPullUtil.next(pp); + if (XmlPullUtil.test(pp, "itdFootPathInfo")) + XmlPullUtil.next(pp); + if (XmlPullUtil.test(pp, "infoLink")) + XmlPullUtil.next(pp); + + XmlPullUtil.enter(pp, "itdStopSeq"); + final List intermediateStops = new LinkedList(); + while (XmlPullUtil.test(pp, "itdPoint")) + { + final int stopId = Integer.parseInt(pp.getAttributeValue(null, "stopID")); + final String stopName = normalizeLocationName(pp.getAttributeValue(null, "name")); + final String stopPosition = normalizePlatform(pp.getAttributeValue(null, "platform"), pp.getAttributeValue(null, + "platformName")); + XmlPullUtil.enter(pp, "itdPoint"); + processItdDateTime(pp, stopTime); + XmlPullUtil.exit(pp, "itdPoint"); + intermediateStops.add(new Stop(new Location(LocationType.STATION, stopId, 0, 0, stopName), stopPosition, stopTime + .getTime())); + } + XmlPullUtil.exit(pp, "itdStopSeq"); + + // remove first and last, because they are not intermediate + if (intermediateStops.get(0).location.id != departureId) + throw new IllegalStateException(); + if (intermediateStops.get(intermediateStops.size() - 1).location.id != arrivalId) + throw new IllegalStateException(); + intermediateStops.remove(0); + intermediateStops.remove(intermediateStops.size() - 1); + + parts.add(new Connection.Trip(line, lineColors(line), destinationId, destination, departureTime.getTime(), + departurePosition, departureId, departure, arrivalTime.getTime(), arrivalPosition, arrivalId, arrival, + intermediateStops)); + } + + XmlPullUtil.exit(pp, "itdPartialRoute"); } + XmlPullUtil.exit(pp, "itdPartialRouteList"); + connections .add(new Connection(id, uri, firstDepartureTime, lastArrivalTime, null, null, 0, firstDeparture, 0, lastArrival, parts)); - XmlPullUtil.skipRestOfTree(pp); + XmlPullUtil.exit(pp, "itdRoute"); } + XmlPullUtil.exit(pp, "itdRouteList"); + return new QueryConnectionsResult(uri, from, via, to, commandLink(sessionId, "tripNext"), connections); } else diff --git a/src/de/schildbach/pte/AbstractHafasProvider.java b/src/de/schildbach/pte/AbstractHafasProvider.java index 2377d6cc..0d285f71 100644 --- a/src/de/schildbach/pte/AbstractHafasProvider.java +++ b/src/de/schildbach/pte/AbstractHafasProvider.java @@ -443,7 +443,7 @@ public abstract class AbstractHafasProvider implements NetworkProvider 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)); + departure.name, arrivalTime, arrivalPos, arrival.id, arrival.name, null)); } else { diff --git a/src/de/schildbach/pte/BahnProvider.java b/src/de/schildbach/pte/BahnProvider.java index a6f177c4..65a17168 100644 --- a/src/de/schildbach/pte/BahnProvider.java +++ b/src/de/schildbach/pte/BahnProvider.java @@ -366,7 +366,7 @@ public final class BahnProvider extends AbstractHafasProvider final Date departureDateTime = ParserUtils.joinDateTime(departureDate, departureTime); final Date arrivalDateTime = ParserUtils.joinDateTime(arrivalDate, arrivalTime); lastTrip = new Connection.Trip(line, line != null ? lineColors(line) : null, 0, null, departureDateTime, - departurePosition, 0, departure, arrivalDateTime, arrivalPosition, 0, arrival); + departurePosition, 0, departure, arrivalDateTime, arrivalPosition, 0, arrival, null); parts.add(lastTrip); if (firstDepartureTime == null) diff --git a/src/de/schildbach/pte/BvgProvider.java b/src/de/schildbach/pte/BvgProvider.java index 02c42aa5..52d398be 100644 --- a/src/de/schildbach/pte/BvgProvider.java +++ b/src/de/schildbach/pte/BvgProvider.java @@ -381,7 +381,7 @@ public final class BvgProvider implements NetworkProvider final String arrival = ParserUtils.resolveEntities(mDetFine.group(10)); parts.add(new Connection.Trip(line, line != null ? LINES.get(line) : null, 0, destination, departureTime, departurePosition, - departureId, departure, arrivalTime, arrivalPosition, arrivalId, arrival)); + departureId, departure, arrivalTime, arrivalPosition, arrivalId, arrival, null)); if (firstDepartureTime == null) firstDepartureTime = departureTime; diff --git a/src/de/schildbach/pte/OebbProvider.java b/src/de/schildbach/pte/OebbProvider.java index db1b1c9f..1bc09d29 100644 --- a/src/de/schildbach/pte/OebbProvider.java +++ b/src/de/schildbach/pte/OebbProvider.java @@ -423,7 +423,7 @@ public class OebbProvider extends AbstractHafasProvider final String arrivalPosition = mDetFine.group(12) != null ? ParserUtils.resolveEntities(mDetFine.group(12)) : null; final Connection.Trip trip = new Connection.Trip(line, lineColors(line), 0, null, detailsDepartureDateTime, - departurePosition, departureId, departure, detailsArrivalDateTime, arrivalPosition, arrivalId, arrival); + departurePosition, departureId, departure, detailsArrivalDateTime, arrivalPosition, arrivalId, arrival, null); connection.parts.add(trip); } else diff --git a/src/de/schildbach/pte/RmvProvider.java b/src/de/schildbach/pte/RmvProvider.java index b97a6deb..4931f404 100644 --- a/src/de/schildbach/pte/RmvProvider.java +++ b/src/de/schildbach/pte/RmvProvider.java @@ -356,7 +356,7 @@ public class RmvProvider extends AbstractHafasProvider final String arrivalPosition = ParserUtils.resolveEntities(mDetFine.group(6)); lastTrip = new Connection.Trip(line, line != null ? lineColors(line) : null, 0, destination, departureTime, - departurePosition, 0, departure, arrivalTime, arrivalPosition, 0, arrival); + departurePosition, 0, departure, arrivalTime, arrivalPosition, 0, arrival, null); parts.add(lastTrip); if (firstDepartureTime == null) diff --git a/src/de/schildbach/pte/dto/Connection.java b/src/de/schildbach/pte/dto/Connection.java index d8ac8b3a..0d1cd9e5 100644 --- a/src/de/schildbach/pte/dto/Connection.java +++ b/src/de/schildbach/pte/dto/Connection.java @@ -27,17 +27,17 @@ import java.util.List; */ public final class Connection implements Serializable { - final public String id; - final public String link; - final public Date departureTime; - final public Date arrivalTime; - final public String line; - final public int[] lineColors; - final public int fromId; - final public String from; - final public int toId; - final public String to; - final public List parts; + public final String id; + public final String link; + public final Date departureTime; + public final Date arrivalTime; + public final String line; + public final int[] lineColors; + public final int fromId; + public final String from; + public final int toId; + public final String to; + public final List parts; public Connection(final String id, final String link, final Date departureTime, final Date arrivalTime, final String line, final int[] lineColors, final int fromId, final String from, final int toId, final String to, final List parts) @@ -85,22 +85,23 @@ public final class Connection implements Serializable public final static class Trip implements Part { - final public String line; - final public int[] lineColors; - final public int destinationId; - final public String destination; - final public Date departureTime; - final public String departurePosition; - final public int departureId; - final public String departure; - final public Date arrivalTime; - final public String arrivalPosition; - final public int arrivalId; - final public String arrival; + public final String line; + public final int[] lineColors; + public final int destinationId; + public final String destination; + public final Date departureTime; + public final String departurePosition; + public final int departureId; + public final String departure; + public final Date arrivalTime; + public final String arrivalPosition; + public final int arrivalId; + public final String arrival; + public final List intermediateStops; public Trip(final String line, final int[] lineColors, final int destinationId, final String destination, final Date departureTime, final String departurePosition, final int departureId, final String departure, final Date arrivalTime, final String arrivalPosition, - final int arrivalId, final String arrival) + final int arrivalId, final String arrival, final List intermediateStops) { this.line = line; this.lineColors = lineColors; @@ -114,6 +115,7 @@ public final class Connection implements Serializable this.arrivalPosition = arrivalPosition; this.arrivalId = arrivalId; this.arrival = arrival; + this.intermediateStops = intermediateStops; } @Override @@ -136,12 +138,12 @@ public final class Connection implements Serializable public final static class Footway implements Part { - final public int min; - final public int departureId; - final public String departure; - final public int arrivalId; - final public String arrival; - final public int arrivalLat, arrivalLon; + public final int min; + public final int departureId; + public final String departure; + public final int arrivalId; + public final String arrival; + public final int arrivalLat, arrivalLon; public Footway(final int min, final int departureId, final String departure, final int arrivalId, final String arrival, final int arrivalLat, final int arrivalLon) diff --git a/src/de/schildbach/pte/dto/Stop.java b/src/de/schildbach/pte/dto/Stop.java new file mode 100644 index 00000000..35d4122f --- /dev/null +++ b/src/de/schildbach/pte/dto/Stop.java @@ -0,0 +1,34 @@ +package de.schildbach.pte.dto; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author Andreas Schildbach + */ +public final class Stop implements Serializable +{ + public final Location location; + public final String position; + public final Date time; + + public Stop(final Location location, final String position, final Date time) + { + this.location = location; + this.position = position; + this.time = time; + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder("Stop("); + builder.append(location); + builder.append(","); + builder.append(position != null ? position : "null"); + builder.append(","); + builder.append(time != null ? time : "null"); + builder.append(")"); + return builder.toString(); + } +} diff --git a/src/de/schildbach/pte/util/XmlPullUtil.java b/src/de/schildbach/pte/util/XmlPullUtil.java index 784c0175..b12f4fbe 100644 --- a/src/de/schildbach/pte/util/XmlPullUtil.java +++ b/src/de/schildbach/pte/util/XmlPullUtil.java @@ -30,6 +30,11 @@ public final class XmlPullUtil throw new IllegalStateException("cannot find <" + tagName + " />"); } + public static void require(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException + { + pp.require(XmlPullParser.START_TAG, null, tagName); + } + /** * enters current tag * @@ -45,7 +50,30 @@ public final class XmlPullUtil pp.next(); } + public static void enter(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException + { + pp.require(XmlPullParser.START_TAG, null, tagName); + enter(pp); + } + public static void exit(final XmlPullParser pp) throws XmlPullParserException, IOException + { + exitSkipToEnd(pp); + + if (pp.getEventType() != XmlPullParser.END_TAG) + throw new IllegalStateException("expecting end tag to exit"); + + pp.next(); + } + + public static void exit(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException + { + exitSkipToEnd(pp); + pp.require(XmlPullParser.END_TAG, null, tagName); + pp.next(); + } + + private static void exitSkipToEnd(final XmlPullParser pp) throws XmlPullParserException, IOException { while (pp.getEventType() != XmlPullParser.END_TAG) { @@ -56,11 +84,6 @@ public final class XmlPullUtil else throw new IllegalStateException(); } - - if (pp.getEventType() != XmlPullParser.END_TAG) - throw new IllegalStateException("expecting end tag to exit"); - - pp.next(); } public static boolean test(final XmlPullParser pp, final String tagName) throws XmlPullParserException @@ -74,11 +97,6 @@ public final class XmlPullUtil pp.next(); } - public static void require(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException - { - pp.require(XmlPullParser.START_TAG, null, tagName); - } - public static String attr(final XmlPullParser pp, final String attrName) { return pp.getAttributeValue(null, attrName);