wiki:Rules/PublicTransportGtfs

Public Transport GTFS

These rules add additional checks for public transportation tagging. One major part are tags in use with GTFS and PTNA (OSM-Wiki, website.

See Public Transport GTFS preset for a corresponding preset.

Help needed

Please, feel free to:

Notes

  • Really beta so far and under development. Expect false positives and lots of changes.
  • The tagging schema is still under heavy development and therefore the rules might change quite often.

Supported Tags

So far checks in the categories Missing tags, Conflicting tags and Value syntax for the following tags exists.

Rules source code

meta {
  title: "Public Transport GTFS";
  link: "https://josm.openstreetmap.de/wiki/Rules/PublicTransportGtfs";
  description: "Special rules for Public transportation supporting GTFS and tags for PTNA. ";
  author: "skyper";
  version: "0.0.21_2020-07-29";
}

/*  -----------------------
 *
 *       Classes
 */

relation[type=route_master][route_master =~ /^(bus|share_taxi|trolleybus|train|tram|light_rail|subway|monorail|ferry)$/] {
  set PtRouteMaster;
}

/* Not only relations as ferry can be a way */
*[type=route][route =~ /^(bus|share_taxi|trolleybus|train|tram|light_rail|subway|monorail|ferry)$/] {
  set PtRoute;
}

relation[gtfs:route_id][type=route_master] > * {
  set ChildMasterRoute_id;
}

*[!aerialway][bus!=yes][share_taxi!=yes][trolleybus!=yes][train!=yes][tram!=yes][light_rail!=yes][subway!=yes][monorail!=yes][ferry!=yes] {
  set noPtVehicle;
}

/*  -----------------------
 *
 *        Rules
 */

/*  -----------------------
 *
 *  missing tag
 */

/* {0.tag} without {1.key} (error level) */

/* route_master and route relations, ToDo ferry on ways */

/* {0.tag} without {1.key} (warning level) */

/* stop_position, platform */
*[public_transport =~ /^(platform|stop_position)$/][public_transport][!local_ref],
*[public_transport =~ /^(platform|stop_position)$/][public_transport][!network] {
  throwWarning: tr("`{0}` without `{1}*`.", "{1.tag}", "{2.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "node public_transport=stop_position";
  assertMatch:   "way public_transport=platform";
  assertNoMatch: "node public_transport=stop_position network=a local_ref=2";
}

/* stop_area */

/* route_master and route relations, ToDo ferry on ways */
relation.PtRouteMaster[type=route_master][!colour],
relation.PtRouteMaster[type=route_master][!fee],
relation.PtRouteMaster[type=route_master][!gtfs:name],
relation.PtRouteMaster[type=route_master][!gtfs:route_id],
relation.PtRouteMaster[type=route_master][!gtfs:source_date],
relation.PtRouteMaster[type=route_master][!network],
relation.PtRouteMaster[type=route_master][!network:short],
relation.PtRouteMaster[type=route_master][!operator],
relation.PtRouteMaster[type=route_master][!operator:short],
relation.PtRouteMaster[type=route_master][!ref],
relation.PtRouteMaster[type=route_master][!source],
relation.PtRouteMaster[type=route_master][!website],
relation.PtRoute[type=route][!colour],
relation.PtRoute[type=route][!duration]["public_transport:version"=2],
relation.PtRoute[type=route][!interval]["public_transport:version"=2],
relation.PtRoute[type=route][!fee],
relation.PtRoute[type=route][!from]["public_transport:version"=2],
relation.PtRoute[type=route][!to]["public_transport:version"=2],
relation.PtRoute[type=route][!gtfs:name]["public_transport:version"=1],
relation.PtRoute[type=route][!gtfs:route_id],
relation.PtRoute[type=route][!gtfs:source_date],
relation.PtRoute[type=route][!network],
relation.PtRoute[type=route][!network:short],
relation.PtRoute[type=route][!opening_hours],
relation.PtRoute[type=route][!operator],
relation.PtRoute[type=route][!operator:short],
relation.PtRoute[type=route][!ref],
relation.PtRoute[type=route][!source],
relation.PtRoute[type=route][!website] {
  throwWarning: tr("Public transport {0} relation without `{1}*`.", "{1.value}", "{2.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "relation type=route route=train";
  assertMatch:   "relation type=route_master route_master=bus";
/* Does not make sense with that many keys above */
/*  assertNoMatch: "relation type=route route=train network:short=MVV";
 *  assertNoMatch: "relation type=route_master route_master=bus colour=green";
 */
}

/* {0.tag} without {1.key} or {2.key} (warning level) */

/* stop_position, platform */
*[public_transport =~ /^(platform|stop_area|stop_position)$/][!ref:IFOPT][!gtfs:stop_id][public_transport] {
  throwWarning: tr("`{0}` without `{1}*` or `{2}*`.", "{3.tag}", "{1.tag}", "{2.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "node public_transport=stop_position train=yes railway=halt";
  assertNoMatch: "node public_transport=stop_position train=yes railway=stop ref:IFOPT=ch:06666:4";
}

/* {0.tag} without {1.key}, {2.key} or {3.key} (warning level) */

/* stop_position, platform */

/* stop_area */

/* route_master and route relations, ToDo ferry on ways */
relation["public_transport:version"=2].PtRoute[!gtfs:shape_id][!gtfs:trip_id][!gtfs:trip_id:sample],
relation[gtfs:route_id].PtRouteMaster[!gtfs:feed][!network:guid][!operator:guid],
relation[gtfs:route_id      ].PtRoute[!gtfs:feed][!network:guid][!operator:guid],
relation[gtfs:shape_id      ].PtRoute[!gtfs:feed][!network:guid][!operator:guid],
relation[gtfs:trip_id       ].PtRoute[!gtfs:feed][!network:guid][!operator:guid],
relation[gtfs:trip_id:sample].PtRoute[!gtfs:feed][!network:guid][!operator:guid] {
  throwWarning: tr("Public transport relation with `{0}` but none of `{1}*`, `{2}*` or `{3}*`.", "{0.tag}", "{2.tag}", "{3.tag}", "{4.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "relation type=route_master route_master=train gtfs:route_id=0-7-242-19j-1";
  assertMatch:   "relation type=route route=bus gtfs:shape_id=0-7-242-19j-1.26.R";
  assertNoMatch: "relation type=route_master route_master=train gtfs:route_id=0-7-242-19j-1 network:guid=DE-BY-MVV";
  assertNoMatch: "relation type=route_master route=bus colour=green";
}

/* {0.tag} without any (warning level) */

/* platform and stop_position */
/* ToDo: Check against parent relation vehicle type */
/* ToDo: Extend to check for parent relation value and offer fix */
*[public_transport =~ /^(platform|stop_position)$/][highway!=bus_stop][public_transport].noPtVehicle {
  throwWarning: tr("`{0}` without serving vehicle type specified.", "{2.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "relation public_transport=platform";
  assertNoMatch: "relation public_transport=platform highway=bus_stop";
} 

/* {0.tag} and {1.tag} without {2.key} (warning level) */

/* stop_position, platform */
node[public_transport=stop_position][train=yes][railway!=stop][public_transport],
*[public_transport =~ /^(platform|stop_position)$/][train=yes][!ref][public_transport] {
  throwWarning: tr("`{0}` with `{1}` but without `{2}`.", "{3.tag}", "{1.tag}", "{2.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "node public_transport=stop_position train=yes railway=halt";
  assertNoMatch: "node public_transport=stop_position train=yes railway=stop ref=2";
}

/* {0.tag} and {1.tag} without {2.key}, {3.key} or {4.key} (warning level) */

/* platform */
*[highway=bus_stop][public_transport =~ /^(platform|stop_position)$/][bus!=yes][share_taxi!=yes][trolleybus!=yes][public_transport] {
  throwWarning: tr("`{0}` with `{1}` but none of `{2}*`, `{3}*` or `{4}*`.", "{5.tag}", "{0.tag}", "{2.tag}", "{3.tag}", "{4.tag}");
  group: tr("Public Transport GTFS: missing tag");
  assertMatch:   "node public_transport=platform highway=bus_stop";
  assertNoMatch: "node public_transport=platform highway=bus_stop bus=yes";
}


/*  -----------------------
 *  value syntax 
 */

/* route_id, shape_id, trip_id */
/* FIXME: Get proper syntax as regex displayed. */
*[gtfs:route_id      ][gtfs:route_id       !~                           /^[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?(;[ ]?[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?)*$/],
*[gtfs:shape_id      ][gtfs:shape_id       !~                           /^[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?\.[1-9][0-9]{0,2}\.[HR](;[ ]?[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?\.[1-9][0-9]{0,2}\.[HR])*$/],
*[gtfs:trip_id       ][gtfs:trip_id        !~ /^[1-9][0-9]{0,3}\.T[023A]\.[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?\.[1-9][0-9]{0,2}\.[HR](;[ ]?[1-9][0-9]{0,3}\.T[023A]\.[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?\.[1-9][0-9]{0,2}\.[HR])*$/],
*[gtfs:trip_id:sample][gtfs:trip_id:sample !~ /^[1-9][0-9]{0,3}\.T[023A]\.[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?\.[1-9][0-9]{0,2}\.[HR](;[ ]?[1-9][0-9]{0,3}\.T[023A]\.[0-9]{1,2}-[A-Z]?[0-9]{1,3}(-[A-Z])?-j[1-9][0-9j]-[1-9][0-9]?\.[1-9][0-9]{0,2}\.[HR])*$/] {
  throwError: tr("Value `{0}` for `{1}=*` does not match value syntax.", "{0.value}", "{0.key}");
/*  throwError: tr("Value `{0}` for `{1}=*` does not match value syntax `{2}`.", "{0.value}", "{0.key}", "{1.value}"); */
  group: tr("Public Transport GTFS: value syntax");
  set GtfsIdSyntax;
  assertMatch:   "relation gtfs:route_id=7-342-j1j-1.H";
  assertNoMatch: "relation gtfs:route_id=7-342-j1j-1";
  assertNoMatch: "relation gtfs:route_id=7-342-j1j-1;7-342-j1j-5";
  assertNoMatch: "relation gtfs:route_id=90-742-B-j20-1";
  assertNoMatch: "relation gtfs:route_id=10-11-I-j20-1";
  assertMatch:   "relation gtfs:shape_id=11-4-I-j20-1.23.";
  assertNoMatch: "relation gtfs:shape_id=11-4-I-j20-1.23.H";
  assertNoMatch: "relation gtfs:shape_id=92-R01-F-j20-1.117.R";
  assertNoMatch: "relation gtfs:shape_id=0-S3-E-j20-2.1.R";
  assertMatch:   "relation gtfs:trip_id=1108.T2.11-4-I-j20-1.10.";
  assertNoMatch: "relation gtfs:trip_id=1108.T2.11-4-I-j20-1.10.H";
  assertNoMatch: "relation gtfs:trip_id=29.T0.7-342-j1j-1.50.H";
  assertNoMatch: "relation gtfs:trip_id=2.TA.90-742-B-j20-1.4.R";
}
/* gtfs:feed, *:guid, gtfs:source_date */
/* FIXME: Get proper syntax as regex displayed. */
*[gtfs:feed    ][gtfs:feed     !~ /^(([A-Z]{2}-){2}[a-zA-Z]{2}.*|[A-Z]{2}-(Alle|Flixbus)|BO-C-Cochabamba|(CH|LU)-[a-zA-Z]{3,}|CO-BOY-[A-Z].+|DE-SPNV|DE-S-und-U-Bahnen|ES-AR-Z-[A-Z].+|FR-IDF-(r|[a-zA-Z]{3,}.*)|MG-T-Antananarivo)$/],
*[network:guid ][network:guid  !~ /^(([A-Z]{2}-){2}[a-zA-Z]{2}.*|[A-Z]{2}-Flixbus|BO-C-Cochabamba|(CH|LU)-[a-zA-Z]{3,}|CO-BOY-[A-Z].+|ES-AR-Z-[A-Z].+|FR-IDF-(r|[a-zA-Z]{3,}.*)|MG-T-Antananarivo)$/],
*[operator:guid][operator:guid !~ /^(([A-Z]{2}-){2}[a-zA-Z]{2}.*|[A-Z]{2}-Flixbus|BO-C-Cochabamba|(CH|LU)-[a-zA-Z]{3,}|CO-BOY-[A-Z].+|ES-AR-Z-[A-Z].+|FR-IDF-(r|[a-zA-Z]{3,}.*)|MG-T-Antananarivo)$/],
*[gtfs:source_date][gtfs:source_date !~ /^20(1[7-9]|20)-(0[1-9]|1[0-2])-(3[01]|[12][0-9]|0[1-9])$/] {
  throwError: tr("Value `{0}` for `{1}=*` does not match value syntax.", "{0.value}", "{0.key}");
/*  throwError: tr("Value `{0}` for `{1}=*` does not match value syntax `{2}`.", "{0.value}", "{0.key}", "{1.value}"); */
  group: tr("Public Transport GTFS: value syntax");
  assertMatch:   "relation gtfs:feed=DE-SH.NAH";
  assertMatch:   "relation gtfs:feed=df-SL-saarVV";
  assertNoMatch: "relation gtfs:feed=DE-SH-NAH.SH";
  assertNoMatch: "relation gtfs:feed=DE-BY-VVM-Mittelschwaben";
  assertNoMatch: "relation gtfs:feed=AU-SA-Adelaide-Metro";
  assertNoMatch: "relation gtfs:feed=DE-SL-saarVV";
  assertMatch:   "relation gtfs:source_date=2016-09-30";
  assertMatch:   "relation gtfs:source_date=2020-9-3";
  assertMatch:   "relation gtfs:source_date=2016-09-30";
  assertNoMatch: "relation gtfs:source_date=2020-09-30";
}
/* ref:IFOPT, gtfs:stop_id */
/* FIXME: Get proper syntax as regex displayed. */
*[ref:IFOPT   ][ref:IFOPT    !~ /^(gen:[0-9]{4}|[a-z]{2}:[0-9]{5}):[1-9][0-9]{0,4}(:[0-9]{1,2}(:([A-Z]+[ ]?)?[1-9][0-9]{0,2}[A-Z]?)?)?$/],
*[gtfs:stop_id][gtfs:stop_id !~ /^(gen:[0-9]{4}|[a-z]{2}:[0-9]{4,5}):[1-9][0-9]{0,4}(:[0-9]{1,2}(:([A-Z]+[ ]?)?[1-9][0-9]{0,2}[A-Z]?)?)?$/] {
  throwError: tr("Value `{0}` for `{1}=*` does not match value syntax.", "{0.value}", "{0.key}");
/*  throwError: tr("Value `{0}` for `{1}=*` does not match value syntax `{2}`.", "{0.value}", "{0.key}", "{1.value}"); */
  group: tr("Public Transport GTFS: value syntax");
  set ErrorSyntaxIFOPT;
  assertMatch:   "node ref:IFOPT=+1";
  assertMatch:   "node ref:IFOPT=aa:aa:09";
  assertMatch:   "node ref:IFOPT=ch:3001:64883";
  assertMatch:   "node ref:IFOPT=gen:91888:5599:0:956R";
  assertNoMatch: "node ref:IFOPT=ch:23001:64883";
  assertNoMatch: "node ref:IFOPT=de:08315:6504:0:14";
  assertNoMatch: "node ref:IFOPT=gen:9188:5599:0:956R";
  assertNoMatch: "node ref:IFOPT=de:09162:1179:3:KIF 1";
  assertNoMatch: "node ref:IFOPT=ch:23005:6";
  assertNoMatch: "node gtfs:stop_id=ch:3001:64883";
}

/* route_id, shape_id, trip_id */
*[gtfs:route_id      ][count(split(";", tag("gtfs:route_id"))) > 1],
*[gtfs:shape_id      ][count(split(";", tag("gtfs:shape_id"))) > 1],
*[gtfs:trip_id       ][count(split(";", tag("gtfs:trip_id"))) > 1],
*[gtfs:trip_id:sample][count(split(";", tag("gtfs:trip_id:sample"))) > 1] {
  throwOther: tr("Multiple values `{0}` for `{1}=*`.", "{0.value}", "{0.key}");
  group: tr("Public Transport GTFS: value syntax");
  set MultipleID;
  assertMatch:   "relation gtfs:route_id=7-342-j1j-1;7-342-j1j-5";
  assertNoMatch: "relation gtfs:route_id=7-342-j1j-1.H";
}

/* old syntax ref:IFOPT */
*[ref:IFOPT   ][ref:IFOPT    =~ /^gen:[0-9]{4}:[1-9][0-9]{0,4}(:[0-9]{1,2}(:([A-Z]+[ ]?)?[1-9][0-9]{0,2}[A-Z]?)?)?$/],
*[gtfs:stop_id][gtfs:stop_id =~ /^gen:[0-9]{4}:[1-9][0-9]{0,4}(:[0-9]{1,2}(:([A-Z]+[ ]?)?[1-9][0-9]{0,2}[A-Z]?)?)?$/] {
  throwOther: tr("Value of `{0}` is in old format.", "{0.key}");
  group: tr("Public Transport GTFS: value syntax");
  assertMatch:   "node ref:IFOPT=gen:9188:5599:0:956R";
  assertNoMatch: "node ref:IFOPT=de:09162:1179:3:KIF 1";
}

/* short ref:IFOPT */
node[public_transport=stop_position][ref:IFOPT   ]!.ErrorSyntaxIFOPT[ref:IFOPT        !~ /^.+(:.+){4}$/],
node[public_transport=platform     ][gtfs:stop_id]!.ErrorSyntaxIFOPT[gtfs:stop_id     !~ /^.+(:.+){4}$/],
node[public_transport=platform     ][ref:IFOPT   ]!.ErrorSyntaxIFOPT[ref:IFOPT        !~ /^.+(:.+){4}$/],
node[public_transport=platform     ][gtfs:stop_id]!.ErrorSyntaxIFOPT[gtfs:stop_id     !~ /^.+(:.+){4}$/],
way[public_transport=platform      ][ref:IFOPT   ]!.ErrorSyntaxIFOPT[ref:IFOPT         !~ /^.+(:.+){3}$/],
way[public_transport=platform      ][gtfs:stop_id]!.ErrorSyntaxIFOPT[gtfs:stop_id      !~ /^.+(:.+){3}$/],
relation[public_transport          ][ref:IFOPT   ]!.ErrorSyntaxIFOPT[ref:IFOPT    !~ /^.+(:.+){3}$/][public_transport =~ /^(platform|stop_area)$/],
relation[public_transport          ][gtfs:stop_id]!.ErrorSyntaxIFOPT[gtfs:stop_id !~ /^.+(:.+){3}$/][public_transport =~ /^(platform|stop_area)$/] {
  throwWarning: tr("Incomplete `{0}` on `{1}`.", "{1.tag}", "{0.tag}");
  group: tr("Public Transport GTFS: value syntax");
  assertMatch:   "node public_transport=platform ref:IFOPT=de:09162:1179:31";
  assertNoMatch: "node public_transport=platform ref:IFOPT=de:09162:1179:53:KIF 1";
  assertNoMatch: "node public_transport=platform ref:IFOPT=DDDD:09162:1179:3:KIF 1";
  assertNoMatch: "way public_transport=platform ref:IFOPT=de:09162:1179:21";
  assertMatch:   "relation public_transport=platform ref:IFOPT=de:09162:1179";
  assertNoMatch: "relation public_transport=platform ref:IFOPT=de:09162:1179:30";
  assertNoMatch: "relation public_transport=platform ref:IFOPT=de:09162:1179:30:KIF 1";
}

/*  -----------------------
 *  conflicting tags
 */

/* ref:IFOPT, gtfs:stop_id, local_ref */
*[public_transport][public_transport =~ /^(platform|stop_position)$/][!(tag("local_ref") == get(regexp_match("^(.*:){4}([A-Z]+[ ]?)?([1-9][0-9]{0,2}[A-Z]?)", tag("ref:IFOPT")), 3))][local_ref][ref:IFOPT],
*[public_transport][public_transport =~ /^(platform|stop_position)$/][!(tag("local_ref") == get(regexp_match("^(.*:){4}([A-Z]+[ ]?)?([1-9][0-9]{0,2}[A-Z]?)", tag("gtfs:stop_id")), 3))][local_ref][ref:IFOPT] {
  throwWarning:  tr("`{0}` conflicts with `{1}`.", "{3.tag}", "{4.tag}");
  group: tr("Public Transport GTFS: conflicting tags");
  assertMatch:   "node public_transport=platform local_ref=14 ref:IFOPT=de:08315:6504:0:1";
  assertMatch:   "node public_transport=platform local_ref=56R ref:IFOPT=gen:9188:5599:0:956R";
  assertNoMatch: "node public_transport=platform local_ref=14 ref:IFOPT=de:08315:6504:0:14";
  assertNoMatch: "node public_transport=platform local_ref=14 ref:IFOPT=de:08315:6504:14";
  assertNoMatch: "node public_transport=platform local_ref=956R ref:IFOPT=gen:9188:5599:0:956R";
  assertNoMatch: "node public_transport=platform local_ref=1 ref:IFOPT=de:09162:1179:3:KIF 1";
}

/* route_id, shape_id, trip_id */
/* FIXME: How to check proper syntax with multiple values */
*[gtfs:trip_id][gtfs:trip_id:sample][!(tag("gtfs:trip_id") == tag("gtfs:trip_id:sample"))] {
throwError: tr("`{1}` and `{0}` are not equal.", "{0.tag}", "{1.tag}");
  group: tr("Public Transport GTFS: conflicting tags");
  assertMatch:   "relation gtfs:trip_id:sample=1108.T5.11-4-I-j20-1.10.H gtfs:trip_id=1108.T2.11-4-I-j20-1.10.H";
  assertNoMatch: "relation gtfs:trip_id:sample=1108.T2.11-4-I-j20-1.10.H gtfs:trip_id=1108.T2.11-4-I-j20-1.10.H";
}
*[gtfs:route_id][gtfs:shape_id      ]!.MultipleID!.GtfsIdSyntax[!(tag("gtfs:route_id") == get(regexp_match("^(.+)\\.[1-9][0-9]?\\.[HR]$", tag("gtfs:shape_id")), 1))],
*[gtfs:route_id][gtfs:trip_id       ]!.MultipleID!.GtfsIdSyntax[!(tag("gtfs:route_id") == get(regexp_match("^[1-9][0-9]{0,3}\\.T[023A]\\.(.+)\\.[1-9][0-9]?\\.[HR]$", tag("gtfs:trip_id")), 1))],
*[gtfs:route_id][gtfs:trip_id:sample]!.MultipleID!.GtfsIdSyntax[!(tag("gtfs:route_id") == get(regexp_match("^[1-9][0-9]{0,3}\\.T[023A]\\.(.+)\\.[1-9][0-9]?\\.[HR]$", tag("gtfs:trip_id:sample")), 3))],
*[gtfs:shape_id][gtfs:trip_id       ]!.MultipleID!.GtfsIdSyntax[!(tag("gtfs:shape_id") == get(regexp_match("^[1-9][0-9]{0,3}\\.T[023A]\\.(.+)$", tag("gtfs:trip_id")), 1))],
*[gtfs:shape_id][gtfs:trip_id:sample]!.MultipleID!.GtfsIdSyntax[!(tag("gtfs:shape_id") == get(regexp_match("^[1-9][0-9]{0,3}\\.T[023A]\\.(.+)$", tag("gtfs:trip_id:sample")), 1))] {
  throwError: tr("`{1}` is not a substring of `{0}`.", "{0.tag}", "{1.tag}"); 
  group: tr("Public Transport GTFS: conflicting tags");
  assertMatch:   "relation gtfs:route_id=7-342-j1j-1 gtfs:shape_id=7-352-j1j-1.17.H";
  assertNoMatch: "relation gtfs:route_id=7-342-j1j-1 gtfs:shape_id=7-342-j1j-1.17.H";
  assertMatch:   "relation gtfs:route_id=11-4-I-j20-1 gtfs:trip_id=1108.T2.11-5-I-j20-1.10.H";
  assertNoMatch: "relation gtfs:route_id=11-4-I-j20-1 gtfs:trip_id=1108.TB2.11-5-I-j20-1.10.H";
  assertNoMatch: "relation gtfs:route_id=11-4-I-j20-1 gtfs:trip_id=1108.T2.11-4-I-j20-1.10.H";
}

/* route_id parent */
/* FIXME: How to ckeck with multiple values? */
/* FIXME: How to display the key-value of the parent? */
relation!.MultipleID[count(split(";", parent_tag("gtfs:route_id"))) == 1].ChildMasterRoute_id {
  set ChildNoMultiID;
}
relation[gtfs:route_id      ][!(parent_tag("gtfs:route_id") == tag("gtfs:route_id"))],
relation[gtfs:shape_id      ][!gtfs:route_id][!(parent_tag("gtfs:route_id") == get(regexp_match("(.+)\\.\\d+\\.[HR]$", tag("gtfs:shape_id")), 1))],
relation[gtfs:trip_id       ][!gtfs:route_id][!gtfs:shape_id][!(parent_tag("gtfs:route_id") == get(regexp_match("^\\d+\\.T[023A]\\.(.+)\\.\\d+\\.[HR]$", tag("gtfs:trip_id")), 1))],
relation[gtfs:trip_id:sample][!gtfs:route_id][!gtfs:shape_id][!(parent_tag("gtfs:route_id") == get(regexp_match("^\\d+\\.T[023A]\\.(.+)\\.\\d+\\.[HR]$", tag("gtfs:trip_id:sample")), 1))]{
  throwWarning:  tr("`{0}` conflicts with `gtfs:route_id=*` of the `route_master` relation.", "{0.tag}");
/*  throwWarning:  tr("`{0}` differs to `route_id={1}` of the `route_master` relation.", "{0.tag}", "{1.value}"); */
  group: tr("Public Transport GTFS: conflicting tags");
/*  assertMatch:   "relation gtfs:shape_id=10-20-I-j20-1.1.R parent_tag(\"type\")=route_master parent_tag(\"gtfs:route_id\")=10-19-I-j20-1";
  assertNoMatch: "relation gtfs:shape_id=10-19-I-j20-1.1.R parent_tag(\"type\")=route_master parent_tag(\"gtfs:route_id\")=10-19-I-j20-1"; */
}


/*  -----------------------
 *  Geometry
 */

/* stop_position */
/* FIXME: How to use assert with :class and evalexpression? */
node[public_transport=stop_position]:unconnected:in-downloaded-area,
node[public_transport=stop_position]:unconnected:new {
  throwError:  tr("`{0}` is not part of any way.", "{0.tag}");
  assertMatch:   "node public_transport=stop_position ";
  assertNoMatch: "node public_transport=stop_position :unconnected !:new !:in-downloaded-area";
  assertNoMatch: "node public_transport=platform :unconnected :new";
/*  assertMatch:   "node public_transport=stop_position :unconnected :in-downloaded-area";
 *  assertMatch:   "node public_transport=stop_position :unconnected :new";
 *  assertNoMatch: "node public_transport=stop_position :unconnected !:new !:in-downloaded-area";
 *  assertNoMatch: "node public_transport=platform :unconnected :new";
 */
}

Rules_PublicTransportGtfs.validator.mapcss, Rules_PublicTransportGtfs.zip

Last modified 8 days ago Last modified on 2020-07-29T17:02:39+02:00