Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate stop names and trip headsigns #169

Merged
merged 1 commit into from
Jan 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ public enum NewGTFSErrorType {
SERVICE_NEVER_ACTIVE(Priority.MEDIUM, "A service code was defined, but is never active on any date."),
SERVICE_UNUSED(Priority.MEDIUM, "A service code was defined, but is never referenced by any trips."),
SHAPE_DIST_TRAVELED_NOT_INCREASING(Priority.MEDIUM, "Shape distance traveled must increase with stop times."),
STOP_DESCRIPTION_SAME_AS_NAME(Priority.LOW, "The description of a stop is identical to its name, so does not add any information."),
STOP_LOW_POPULATION_DENSITY(Priority.HIGH, "A stop is located in a geographic area with very low human population density."),
STOP_NAME_MISSING(Priority.MEDIUM, "A stop does not have a name."),
STOP_GEOGRAPHIC_OUTLIER(Priority.HIGH, "This stop is located very far from the middle 90% of stops in this feed."),
STOP_UNUSED(Priority.MEDIUM, "This stop is not referenced by any trips."),
TRIP_EMPTY(Priority.HIGH, "This trip is defined but has no stop times."),
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."),
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'"),
TRIP_NEVER_ACTIVE(Priority.MEDIUM, "A trip is defined, but its service is never running on any date."),
ROUTE_UNUSED(Priority.HIGH, "This route is defined but has no trips."),
TRAVEL_DISTANCE_ZERO(Priority.MEDIUM, "The vehicle does not cover any distance between the last stop and this one."),
Expand Down
38 changes: 37 additions & 1 deletion src/main/java/com/conveyal/gtfs/validator/NamesValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.conveyal.gtfs.error.SQLErrorStorage;
import com.conveyal.gtfs.loader.Feed;
import com.conveyal.gtfs.model.Route;
import com.conveyal.gtfs.model.Stop;
import com.conveyal.gtfs.model.Trip;

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

Expand Down Expand Up @@ -41,7 +43,41 @@ public void validate() {
// TODO we want some additional checking for extended route types.
}
}
// TODO Check trips and all other tables.
// Check stops
for (Stop stop : feed.stops) {
String name = normalize(stop.stop_name);
String desc = normalize(stop.stop_desc);
// Stops must be named.
if (name.isEmpty()) {
registerError(stop, STOP_NAME_MISSING);
}
// If provided, the description of a stop should be more informative than its name.
if (!desc.isEmpty() && desc.equals(name)) {
registerError(stop, STOP_DESCRIPTION_SAME_AS_NAME, desc);
}
}
// Check trips
for (Trip trip : feed.trips) {
String headsign = normalize(trip.trip_headsign);
// TODO: check trip short name?
// String shortName = normalize(trip.trip_short_name);
Route route = feed.routes.get(trip.route_id);
String routeShortName = "", routeLongName = "";
if (route != null) {
routeShortName = normalize(route.route_short_name);
routeLongName = normalize(route.route_long_name);
}
// Trip headsign should not duplicate route name.
if (!headsign.isEmpty() && (headsign.contains(routeShortName) || headsign.contains(routeLongName))) {
registerError(trip, TRIP_HEADSIGN_CONTAINS_ROUTE_NAME, headsign);
}
// Trip headsign should not begin with "to" or "towards" (note: headsign normalized to lowercase). Headsigns
// should follow one of the patterns defined in the best practices: http://gtfs.org/best-practices#tripstxt
if (headsign.startsWith("to ") || headsign.startsWith("towards ")) {
registerError(trip, TRIP_HEADSIGN_SHOULD_DESCRIBE_DESTINATION_OR_WAYPOINTS, headsign);
}
}
// TODO Are there other tables we're not checking?
}

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