Skip to content

Commit 57566ec

Browse files
committed
feat(validator): validate stop names and trip headsigns
refs #167
1 parent cab706f commit 57566ec

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java

+4
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@ public enum NewGTFSErrorType {
4444
SERVICE_NEVER_ACTIVE(Priority.MEDIUM, "A service code was defined, but is never active on any date."),
4545
SERVICE_UNUSED(Priority.MEDIUM, "A service code was defined, but is never referenced by any trips."),
4646
SHAPE_DIST_TRAVELED_NOT_INCREASING(Priority.MEDIUM, "Shape distance traveled must increase with stop times."),
47+
STOP_DESCRIPTION_SAME_AS_NAME(Priority.LOW, "The description of a stop is identical to its name, so does not add any information."),
4748
STOP_LOW_POPULATION_DENSITY(Priority.HIGH, "A stop is located in a geographic area with very low human population density."),
49+
STOP_NAME_MISSING(Priority.MEDIUM, "A stop does not have a name."),
4850
STOP_GEOGRAPHIC_OUTLIER(Priority.HIGH, "This stop is located very far from the middle 90% of stops in this feed."),
4951
STOP_UNUSED(Priority.MEDIUM, "This stop is not referenced by any trips."),
5052
TRIP_EMPTY(Priority.HIGH, "This trip is defined but has no stop times."),
53+
TRIP_HEADSIGN_CONTAINS_ROUTE_NAME(Priority.LOW, "A trip headsign contains the route name, but should only contain information to distinguish it from other trips for the route."),
54+
TRIP_HEADSIGN_SHOULD_DESCRIBE_DESTINATION_OR_WAYPOINTS(Priority.LOW, "A trip headsign begins with 'to' or 'towards', but should begin with destination or direction and optionally include waypoints with 'via'"),
5155
TRIP_NEVER_ACTIVE(Priority.MEDIUM, "A trip is defined, but its service is never running on any date."),
5256
ROUTE_UNUSED(Priority.HIGH, "This route is defined but has no trips."),
5357
TRAVEL_DISTANCE_ZERO(Priority.MEDIUM, "The vehicle does not cover any distance between the last stop and this one."),

src/main/java/com/conveyal/gtfs/validator/NamesValidator.java

+37-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.conveyal.gtfs.error.SQLErrorStorage;
44
import com.conveyal.gtfs.loader.Feed;
55
import com.conveyal.gtfs.model.Route;
6+
import com.conveyal.gtfs.model.Stop;
7+
import com.conveyal.gtfs.model.Trip;
68

79
import static com.conveyal.gtfs.error.NewGTFSErrorType.*;
810

@@ -41,7 +43,41 @@ public void validate() {
4143
// TODO we want some additional checking for extended route types.
4244
}
4345
}
44-
// TODO Check trips and all other tables.
46+
// Check stops
47+
for (Stop stop : feed.stops) {
48+
String name = normalize(stop.stop_name);
49+
String desc = normalize(stop.stop_desc);
50+
// Stops must be named.
51+
if (name.isEmpty()) {
52+
registerError(stop, STOP_NAME_MISSING);
53+
}
54+
// If provided, the description of a stop should be more informative than its name.
55+
if (!desc.isEmpty() && desc.equals(name)) {
56+
registerError(stop, STOP_DESCRIPTION_SAME_AS_NAME, desc);
57+
}
58+
}
59+
// Check trips
60+
for (Trip trip : feed.trips) {
61+
String headsign = normalize(trip.trip_headsign);
62+
// TODO: check trip short name?
63+
// String shortName = normalize(trip.trip_short_name);
64+
Route route = feed.routes.get(trip.route_id);
65+
String routeShortName = "", routeLongName = "";
66+
if (route != null) {
67+
routeShortName = normalize(route.route_short_name);
68+
routeLongName = normalize(route.route_long_name);
69+
}
70+
// Trip headsign should not duplicate route name.
71+
if (!headsign.isEmpty() && (headsign.contains(routeShortName) || headsign.contains(routeLongName))) {
72+
registerError(trip, TRIP_HEADSIGN_CONTAINS_ROUTE_NAME, headsign);
73+
}
74+
// Trip headsign should not begin with "to" or "towards" (note: headsign normalized to lowercase). Headsigns
75+
// should follow one of the patterns defined in the best practices: http://gtfs.org/best-practices#tripstxt
76+
if (headsign.startsWith("to ") || headsign.startsWith("towards ")) {
77+
registerError(trip, TRIP_HEADSIGN_SHOULD_DESCRIBE_DESTINATION_OR_WAYPOINTS, headsign);
78+
}
79+
}
80+
// TODO Are there other tables we're not checking?
4581
}
4682

4783
/** @return a non-null String that is lower case and has no leading or trailing whitespace */

0 commit comments

Comments
 (0)