├── .gitignore ├── package.json ├── uriStrategy.md ├── LICENSE ├── lib ├── helpers │ ├── TriplesToJSONLD.js │ ├── TransformerPicker.js │ └── ZipToTriples.js ├── gtfs-csv2rdf.js └── transformers │ ├── AgenciesTransformer.js │ ├── FrequenciesTransformer.js │ ├── ShapesTransformer.js │ ├── CalendarDatesTransformer.js │ ├── FareRulesTransformer.js │ ├── TransfersTransformer.js │ ├── FareAttributesTransformer.js │ ├── TripsTransformer.js │ ├── CalendarTransformer.js │ ├── FeedInfoTransformer.js │ ├── RoutesTransformer.js │ ├── StopsTransformer.js │ └── StopTimesTransformer.js ├── README.md └── gtfs-csv2rdf /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | *.ttl 3 | *.sparql 4 | *.jsonld 5 | 6 | 7 | # Logs 8 | logs 9 | *.log 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # Deployed apps should consider commenting this line out: 30 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 31 | node_modules 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gtfs-csv2rdf", 3 | "version": "1.1.5", 4 | "description": "Mapping script from gtfs csv to gtfs rdf", 5 | "main": "lib/gtfs-csv2rdf.js", 6 | "bin": "./gtfs-csv2rdf", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/OpenTransport/gtfs-csv2rdf.git" 13 | }, 14 | "keywords": [ 15 | "GTFS" 16 | ], 17 | "author": "Pieter Colpaert", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/OpenTransport/gtfs-csv2rdf/issues" 21 | }, 22 | "dependencies": { 23 | "JSONStream": "^1.0.4", 24 | "csv": "~0.4.0", 25 | "jsonld": "^1.1.0", 26 | "jsonld-stream": "^1.0.2", 27 | "moment": "^2.10.3", 28 | "n3": "~0.4.0", 29 | "unzip": "~0.1.9" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /uriStrategy.md: -------------------------------------------------------------------------------- 1 | # URI strategy for gtfs.org 2 | 3 | ## Ontology 4 | 5 | Hosted at http://vocab.gtfs.org/terms 6 | 7 | All terms are added directly behind this namespace URI with a # in between. 8 | 9 | ## Data 10 | 11 | ### Feeds 12 | 13 | The feed gets created with a version number attached: `http://data.gtfs.org/{feed_name}/{feed_version}`. This version is needed as local identifiers are not persistent when version numbers change. 14 | 15 | ### Stops, Trips, Routes, Zones... 16 | 17 | Everything with a single id in the original GTFS spec is mapped like this (example for stops): `http://data.gtfs.org/{feed_name}/{feed_version}/stops/{local_id}` 18 | 19 | ### Stop Times 20 | 21 | Stop Times don't have a single URI. It is referred to as the vehicle stopping at a certain gtfs:Stop when on a certain gtfs:Trip. Therefore, we have this template for Stop Times: 22 | 23 | `http://data.gtfs.org/{feed_name}/{feed_version}/stops/{local_id}` 24 | 25 | The URIs, when being dereferenced will get a HTTP 303 towards the triple pattern fragment at our server with server filled out. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 OpenTransport 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/helpers/TriplesToJSONLD.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This helper class makes JSON-LD objects from a triples stream. 3 | * From the moment a subject is given which has got nothing to do with the current being composed object, the object is pushed to the client. 4 | * The script works in the philosophy that related triples are going to be streamed out next to each other. 5 | * 6 | * @author Pieter Colpaert 7 | */ 8 | var TriplesToJSONLDStream = require('jsonld-stream').TriplesToJSONLDStream; 9 | 10 | function TriplesToJSONLD () { 11 | return new TriplesToJSONLDStream({ 12 | '@context' : { 13 | 'gtfs' : 'http://vocab.gtfs.org/terms#', 14 | 'geo' : 'http://www.w3.org/2003/01/geo/wgs84_pos#', 15 | 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 16 | 'time' : 'http://www.w3.org/2006/time#', 17 | 'foaf' : 'http://xmlns.com/foaf/0.1/', 18 | 'dct' : 'http://purl.org/dc/terms/', 19 | 'rdfs' : 'http://www.w3.org/2000/01/rdf-schema#', 20 | 'owl' : 'http://www.w3.org/2002/07/owl#', 21 | 'xsd' : 'http://www.w3.org/2001/XMLSchema#', 22 | 'skos' : 'http://www.w3.org/2004/02/skos/core#', 23 | 'schema' : 'http://schema.org/', 24 | 'dcat' : 'http://www.w3.org/ns/dcat#' 25 | } 26 | }); 27 | } 28 | 29 | module.exports = TriplesToJSONLD; 30 | -------------------------------------------------------------------------------- /lib/gtfs-csv2rdf.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | StopsTransformer : require('./transformers/StopsTransformer.js'), 3 | AgenciesTransformer : require('./transformers/AgenciesTransformer.js'), 4 | RoutesTransformer : require('./transformers/RoutesTransformer.js'), 5 | TripsTransformer : require('./transformers/TripsTransformer.js'), 6 | StopTimesTransformer : require('./transformers/StopTimesTransformer.js'), 7 | CalendarTransformer : require('./transformers/CalendarTransformer.js'), 8 | CalendarDatesTransformer : require('./transformers/CalendarDatesTransformer.js'), 9 | FeedInfoTransformer : require('./transformers/FeedInfoTransformer.js'), 10 | FareAttributesTransformer : require('./transformers/FareAttributesTransformer.js'), 11 | FareRulesTransformer : require('./transformers/FareRulesTransformer.js'), 12 | ShapesTransformer : require('./transformers/ShapesTransformer.js'), 13 | FrequenciesTransformer : require('./transformers/FrequenciesTransformer.js'), 14 | TransfersTransformer : require('./transformers/TransfersTransformer.js'), 15 | //a helper function from zip to triples 16 | zipToTriples : require('./helpers/ZipToTriples.js'), 17 | //a helper function to pick a transformer based on a filename 18 | pickTransformer : require('./helpers/TransformerPicker.js'), 19 | //a helper transformer: from triples stream to json-ld 20 | TriplesToJSONLD : require('./helpers/TriplesToJSONLD.js') 21 | }; 22 | -------------------------------------------------------------------------------- /lib/helpers/TransformerPicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns a transformer for the specific filename 3 | * @param filename is the file name according to the GTFS spec (e.g., fare_attributes.txt) 4 | */ 5 | function pickTransformer (filename, options) { 6 | //first check whether options are okay 7 | if (!options) { 8 | throw 'Options not given. We want a feedname and a version.'; 9 | } 10 | 11 | if (!options.baseuri) { 12 | throw 'Please set baseuri'; 13 | } 14 | 15 | if (!options.feedname) { 16 | throw 'Please set feedname'; 17 | } 18 | 19 | var gtfsFilenames = { 20 | 'stops.txt' : require('../transformers/StopsTransformer.js'), 21 | 'agency.txt' : require('../transformers/AgenciesTransformer.js'), 22 | 'routes.txt' : require('../transformers/RoutesTransformer.js'), 23 | 'trips.txt' : require('../transformers/TripsTransformer.js'), 24 | 'stop_times.txt' : require('../transformers/StopTimesTransformer.js'), 25 | 'calendar.txt' : require('../transformers/CalendarTransformer.js'), 26 | 'calendar_dates.txt' : require('../transformers/CalendarDatesTransformer.js'), 27 | 'feed_info.txt' : require('../transformers/FeedInfoTransformer.js'), 28 | 'fare_attributes.txt' : require('../transformers/FareAttributesTransformer.js'), 29 | 'fare_rules.txt' : require('../transformers/FareRulesTransformer.js'), 30 | 'shapes.txt' : require('../transformers/ShapesTransformer.js'), 31 | 'frequencies.txt' : require('../transformers/FrequenciesTransformer.js'), 32 | 'transfers.txt' : require('../transformers/TransfersTransformer.js'), 33 | }; 34 | 35 | if (gtfsFilenames[filename]) { 36 | return new gtfsFilenames[filename](options); 37 | } else { 38 | return null; 39 | } 40 | }; 41 | 42 | module.exports = pickTransformer; 43 | -------------------------------------------------------------------------------- /lib/transformers/AgenciesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(AgenciesTransformer, Transform); 8 | 9 | function AgenciesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | AgenciesTransformer.prototype._transform = function (data, encoding, done) { 16 | var subject = this._feedbaseuri + "/agencies/" + data["agency_id"]; 17 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Agency"}); 18 | 19 | // foaf:name triple 20 | if (data["agency_name"]) { 21 | this.push({ subject: subject, predicate: "http://xmlns.com/foaf/0.1/name", object : '"' + data["agency_name"] + '"^^http://www.w3.org/2001/XMLSchema#string' }); 22 | } 23 | 24 | // foaf:page triple 25 | if (data["agency_url"]) { 26 | this.push({ subject: subject, predicate: "http://xmlns.com/foaf/0.1/page", object : data["agency_url"] }); 27 | } 28 | 29 | // foaf:phone triple 30 | if (data["agency_phone"]) { 31 | this.push({ subject: subject, predicate: "http://xmlns.com/foaf/0.1/phone", object :'"' + data["agency_phone"]+'"' }); 32 | } 33 | // gtfs:fareUrl triple 34 | if (data["agency_fare_url"]) { 35 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#fareUrl", object : data["agency_fare_url"] }); 36 | } 37 | 38 | if (data["agency_timezone"]) { 39 | this.push({ subject: subject, predicate: "http://www.w3.org/2006/time#timeZone", object : '"' + data["agency_timezone"] + '"^^http://www.w3.org/2001/XMLSchema#string' }); 40 | } 41 | 42 | done(); 43 | }; 44 | 45 | module.exports = AgenciesTransformer; 46 | -------------------------------------------------------------------------------- /lib/transformers/FrequenciesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(FrequenciesTransformer, Transform); 8 | 9 | function FrequenciesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | FrequenciesTransformer.prototype._transform = function (data, encoding, done) { 16 | if (data["trip_id"] && data["start_time"] && data["end_time"] && data["headway_secs"]) { 17 | var subject = this._feedbaseuri + "/trips/" + data["trip_id"] + "/frequencies/" + data["start_time"] + data["end_time"]; 18 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Frequency"}); 19 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#startTime", object: '"' + data["start_time"] + '"'}); 20 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#endTime", object: '"' + data["end_time"] + '"'}); 21 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#headwaySeconds", object: '"' + data["headway_secs"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 22 | if (data["exact_times"]) { 23 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#headwaySeconds", object: '"' + (data["exact_times"] === "1"?"true":"false") + '"^^http://www.w3.org/2001/XMLSchema#boolean'}); 24 | } else { 25 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#headwaySeconds", object: '"false"^^http://www.w3.org/2001/XMLSchema#boolean'}); 26 | } 27 | } else { 28 | console.error("Frequency doesn't contain all required fields"); 29 | } 30 | done(); 31 | }; 32 | 33 | module.exports = FrequenciesTransformer; 34 | -------------------------------------------------------------------------------- /lib/transformers/ShapesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(ShapesTransformer, Transform); 8 | 9 | function ShapesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | ShapesTransformer.prototype._transform = function (data, encoding, done) { 16 | var subject = this._feedbaseuri + "/shapes/" + data["shape_id"]; 17 | this.push({subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Shape"}); 18 | if (data["shape_pt_lat"] && data["shape_pt_lon"] && data["shape_pt_sequence"]) { 19 | var point = subject + "/shapepoints/" + data["shape_pt_sequence"]; 20 | this.push({subject: subject, predicate: "http://vocab.gtfs.org/terms#shapePoint", object: point}); 21 | this.push({subject: point, predicate: "http://www.w3.org/2003/01/geo/wgs84_pos#lat", object : '"' + data["shape_pt_lat"] + '"'}); 22 | this.push({subject: point, predicate: "http://www.w3.org/2003/01/geo/wgs84_pos#long", object : '"' + data["shape_pt_lon"] + '"'}); 23 | this.push({subject: point, predicate: "http://vocab.gtfs.org/terms#pointSequence", object : '"' + data["shape_pt_sequence"] + '"^^http://www.w3.org/2001/XMLSchema#nonNegativeInteger' }); 24 | 25 | if (data["shape_dist_traveled"]) { 26 | this.push({subject: point, predicate: "http://vocab.gtfs.org/terms#distanceTraveled", object : '"' + data["shape_dist_traveled"] + '"^^http://www.w3.org/2001/XMLSchema#nonNegativeInteger' }); 27 | } 28 | 29 | } else { 30 | console.error("Required column not set in shape_points. Data dump follows:"); 31 | console.error(data); 32 | } 33 | 34 | done(); 35 | }; 36 | 37 | module.exports = ShapesTransformer; 38 | -------------------------------------------------------------------------------- /lib/transformers/CalendarDatesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'), 6 | moment = require('moment'); 7 | 8 | util.inherits(CalendarDatesTransformer, Transform); 9 | 10 | function CalendarDatesTransformer (options) { 11 | this._feedbaseuri = options.baseuri; 12 | this._options = options; 13 | Transform.call(this, {objectMode : true}); 14 | } 15 | 16 | CalendarDatesTransformer.prototype._transform = function (data, encoding, done) { 17 | var subject = this._feedbaseuri + "/services/" + data["service_id"]; 18 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Service"}); 19 | var servicerule = subject + "/servicerules/" + data["date"]; 20 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#serviceRule", object: servicerule}); 21 | this.push({ subject: servicerule, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#ServiceRule"}); 22 | this.push({ subject: servicerule, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#CalendarDateRule"}); 23 | 24 | if (data["exception_type"]) { 25 | //1 is added for the certain date 26 | //2 is removed for the certain date 27 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#dateAddition", object: '"' + (data["exception_type"] === "1"?"true":"false") + '"^^http://www.w3.org/2001/XMLSchema#boolean'}); 28 | } 29 | 30 | if (data["date"]){ 31 | this.push({ subject: servicerule, predicate: "http://purl.org/dc/terms/date", object: '"' + moment(data["date"], "YYYYMMDD").format("YYYY-MM-DD") + '"^^http://www.w3.org/2001/XMLSchema#date'}); 32 | } 33 | 34 | done(); 35 | }; 36 | 37 | module.exports = CalendarDatesTransformer; 38 | -------------------------------------------------------------------------------- /lib/helpers/ZipToTriples.js: -------------------------------------------------------------------------------- 1 | var unzip = require('unzip'); 2 | var csv = require('csv'); 3 | var pickTransformer = require('./TransformerPicker.js'); 4 | 5 | /** 6 | * This function pipes an fstream of a gtfs zip file to a set of outstreams, depending on what is requested. Extracting the zip-file itself happens in here. 7 | * @param zipstream is an fstream configured with a to be read zip file 8 | * @param outstream is an output stream 9 | */ 10 | function zipStreamToTriples (zipstream, outstream, options) { 11 | //first check whether options are okay 12 | if (!options) { 13 | throw "Options not given. We want a feedname and a version."; 14 | } 15 | if (!options.feedname) { 16 | throw "Please set feedname"; 17 | } 18 | if (!options.baseuri) { 19 | throw "Please set baseuri"; 20 | } 21 | 22 | var lastTransformer = null; 23 | //Process the zipstream 24 | var stream = zipstream.pipe(unzip.Parse()); 25 | stream.on('entry', function (entry) { 26 | var fileName = entry.path; 27 | var type = entry.type; // 'Directory' or 'File' 28 | var size = entry.size; 29 | var transformer = pickTransformer(fileName, options); 30 | lastTransformer = transformer; 31 | if (transformer) { 32 | entry.pipe(csv.parse({'columns' : true, 'relax': true })) 33 | .pipe(transformer) 34 | .pipe(outstream, {'end' : false}); 35 | transformer.on('finish', function () { 36 | //small zip-stream hack: if after 2 seconds, there's no other transformer, it means our zipstream ended. 37 | setTimeout(function () { 38 | if (lastTransformer === transformer) { 39 | stream.end(); 40 | outstream.end(); 41 | } 42 | },200); 43 | }); 44 | lastTransformer = transformer; 45 | } else { 46 | console.error('draining ' + fileName); 47 | entry.autodrain(); 48 | } 49 | }); 50 | 51 | outstream.on('finish', function () { 52 | console.error('done!'); 53 | }); 54 | }; 55 | 56 | module.exports = zipStreamToTriples; 57 | -------------------------------------------------------------------------------- /lib/transformers/FareRulesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(FareRulesTransformer, Transform); 8 | 9 | function FareRulesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | FareRulesTransformer.prototype._transform = function (data, encoding, done) { 16 | if (!data["fare_id"]) { 17 | console.error("Parser error: could not find a fare_id. Data follows:"); 18 | console.error(data); 19 | } else { 20 | var subject = this._feedbaseuri + "/fareclasses/" + data["fare_id"] + "/farerules/" + (data["route_id"]?data["route_id"]:"") + (data["origin_id"]?data["origin_id"]:"") + (data["destination_id"]?data["destination_id"]:"") + (data["contains_id"]?data["contains_id"]:""); 21 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#FareRule"}); 22 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#fareClass", object: this._feedbaseuri + "/fareclasses/" + data["fare_id"]}); 23 | if (data["route_id"]) { 24 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#route", object: this._feedbaseuri + "/routes/" + data["route_id"]}); 25 | } 26 | if (data["origin_id"]) { 27 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#originZone", object: this._feedbaseuri + "/zones/" + data["origin_id"]}); 28 | } 29 | if (data["destination_id"]) { 30 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#destinationZone", object: this._feedbaseuri + "/zones/" + data["destination_id"]}); 31 | } 32 | if (data["contains_id"]) { 33 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#zone", object: this._feedbaseuri + "/zones/" + data["contains_id"]}); 34 | } 35 | } 36 | done(); 37 | }; 38 | 39 | module.exports = FareRulesTransformer; 40 | -------------------------------------------------------------------------------- /lib/transformers/TransfersTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(TransfersTransformer, Transform); 8 | 9 | function TransfersTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | TransfersTransformer.prototype._transform = function (data, encoding, done) { 16 | if (data["from_stop_id"] && data["to_stop_id"]) { 17 | var subject = this._feedbaseuri + "/transferrules/" + data["from_stop_id"] + "-" + data["to_stop_id"]; 18 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#TransferRule"}); 19 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#originStop", object: this._feedbaseuri + "/stops/" + data["from_stop_id"]}); 20 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#destinationStop", object: this._feedbaseuri + "/stops/" + data["to_stop_id"]}); 21 | if (data["transfer_type"]) { 22 | if (data["transfer_type"] === "0") { 23 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transferType", object: "http://vocab.gtfs.org/terms#Recommended"}); 24 | } else if (data["transfer_type"] === "1") { 25 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transferType", object: "http://vocab.gtfs.org/terms#EnsuredTransfer"}); 26 | } else if (data["transfer_type"] === "2") { 27 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transferType", object: "http://vocab.gtfs.org/terms#MinimumTimeTransfer"}); 28 | } else if (data["transfer_type"] === "3") { 29 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transferType", object: "http://vocab.gtfs.org/terms#NoTransfer"}); 30 | } 31 | } else { 32 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transferType", object: "http://vocab.gtfs.org/terms#Recommended"}); 33 | } 34 | if (data["min_transfer_time"]) { 35 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#minimumTransferTime", object : '"' + data["min_transfer_time"] + '"^^http://www.w3.org/2001/XMLSchema#nonNegativeInteger' }); 36 | } 37 | } else { 38 | console.error("Transfer does not contain all required field. Data follows:"); 39 | console.error(data); 40 | } 41 | done(); 42 | }; 43 | 44 | module.exports = TransfersTransformer; 45 | -------------------------------------------------------------------------------- /lib/transformers/FareAttributesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(FareAttributesTransformer, Transform); 8 | 9 | function FareAttributesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | FareAttributesTransformer.prototype._transform = function (data, encoding, done) { 16 | var subject = this._feedbaseuri + "/fareclasses/" + data["fare_id"]; 17 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#FareClass"}); 18 | 19 | if (data["price"]) { 20 | this.push({ subject: subject, predicate: "http://schema.org/price", object : '"' + data["price"] + '"' }); 21 | } 22 | 23 | if (data["currency_type"]) { 24 | this.push({ subject: subject, predicate: "http://schema.org/priceCurrency", object : '"' + data["currency_type"] + '"' }); 25 | } 26 | 27 | if (data["payment_method"]) { 28 | if (data["payment_method"] === 1) { 29 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#paymentMethod", object : "http://vocab.gtfs.org/terms#BeforeBoarding" }); 30 | } else { 31 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#paymentMethod", object : "http://vocab.gtfs.org/terms#OnBoard" }); 32 | } 33 | } 34 | 35 | if (data["transfers"]) { 36 | if (data["payment_method"] === "0") { 37 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transfers", object : "http://vocab.gtfs.org/terms#NoTransfersAllowed"}); 38 | } else if (data["payment_method"] === "1") { 39 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transfers", object : "http://vocab.gtfs.org/terms#OneTransfersAllowed"}); 40 | } else if (data["payment_method"] === "2") { 41 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transfers", object : "http://vocab.gtfs.org/terms#TwoTransfersAllowed"}); 42 | } 43 | } else { 44 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transfers", object : "http://vocab.gtfs.org/terms#UnlimitedTransfersAllowed"}); 45 | } 46 | 47 | if (data["transfer_duration"]) { 48 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#transferExpiryTime", object : '"' + data["transfer_duration"] + '"^^http://www.w3.org/2001/XMLSchema#nonNegativeInteger'}); 49 | } 50 | done(); 51 | }; 52 | 53 | module.exports = FareAttributesTransformer; 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gtfs-csv2rdf 2 | 3 | [![npm version](https://badge.fury.io/js/gtfs-csv2rdf.svg)](https://badge.fury.io/js/gtfs-csv2rdf) 4 | 5 | Mapping library which transforms GTFS CSV files into GTFS triples using the [Linked GTFS vocabulary](http://vocab.gtfs.org). 6 | 7 | If you need route planning over Linked Data, then please check out the [Linked Connections framework](https://linkedconnections.org) instead. Transforming GTFS to Linked Data will _not_ return you the data in a format that is useful for route planning. 8 | 9 | ## Use 10 | 11 | Requirements: 12 | * node js 13 | 14 | Install using `npm install gtfs-csv2rdf --save` 15 | 16 | ### Command Line 17 | 18 | In this case, you can install it globally using `npm install -g gtfs-csv2rdf` 19 | 20 | ```bash 21 | # First argument: path to gtfs 22 | # Second argument: the base URI 23 | # Third argument (optional): the requested format (turtle (default), ntriples or jsonld) 24 | gtfs-csv2rdf path-to-gtfs.zip http://data.gtfs.org/sample-feed/0.1/ turtle > gtfsintriples.ttl 25 | ``` 26 | ### As a nodejs library 27 | 28 | By example: 29 | 30 | ```javascript 31 | var fs = require('fs'); 32 | var N3 = require('n3'); 33 | var gtfs-csv2rdf = require('gtfs-csv2rdf').zipToTriples; 34 | var path = "/path/to/gtfs.zip"; 35 | if (/(.*\/)?(.*?)\.zip/.exec(path)) { 36 | var feedname = /(.*\/)?(.*?)\.zip/.exec(path)[2]; 37 | } else { 38 | throw "Not a zip file: " + path; 39 | } 40 | //create the writer of turtle file towards stdout 41 | var streamWriter = new N3.StreamWriter({ 'gtfs': 'http://vocab.gtfs.org/terms#', 42 | 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 43 | 'foaf' : 'http://xmlns.com/foaf/0.1/', 44 | 'dct' : 'http://purl.org/dc/terms/', 45 | 'rdfs' : 'http://www.w3.org/2000/01/rdf-schema#', 46 | 'owl' : 'http://www.w3.org/2002/07/owl#', 47 | 'xsd' : 'http://www.w3.org/2001/XMLSchema#', 48 | 'vann' : 'http://purl.org/vocab/vann/', 49 | 'skos' : 'http://www.w3.org/2004/02/skos/core#', 50 | 'dcat' : 'http://www.w3.org/ns/dcat#'}); 51 | streamWriter.pipe(process.stdout); 52 | var options = { 53 | feedname : feedname, 54 | baseuri : "http://data.example.org/sample-feed/0.1/" 55 | }; 56 | gtfscsv2rdf(fs.createReadStream(path), streamWriter, options); 57 | ``` 58 | 59 | For other functions, check out the [main file of the library](https://github.com/OpenTransport/gtfs-csv2rdf/blob/master/lib/gtfs-csv2rdf.js) 60 | -------------------------------------------------------------------------------- /gtfs-csv2rdf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* Pieter Colpaert */ 3 | 4 | /** 5 | * This script reads a zipped GTFS archive and maps it into RDF (text/turtle, application/ld+json or N-Triples) in a streaming fashion 6 | */ 7 | 8 | var fs = require('fs'), 9 | N3 = require('n3'), 10 | mapper = require('./lib/gtfs-csv2rdf.js').zipToTriples, 11 | TriplesToJSONLDStream = require('jsonld-stream').TriplesToJSONLDStream, 12 | JSONLDSerializer = require('jsonld-stream').Serializer; 13 | 14 | var die = function (msg) { 15 | console.log(msg); 16 | process.exit(); 17 | } 18 | 19 | //check whether the location of the zip has been set and zip exists 20 | var path = "", 21 | version = "", 22 | baseuri = ""; 23 | 24 | if (process.argv[2]) { 25 | path = process.argv[2]; 26 | }else { 27 | die("Give a path towards your gtfs feed as a first argument"); 28 | } 29 | 30 | if (process.argv[3]) { 31 | baseuri = process.argv[3].replace(/\/+$/,''); 32 | } else { 33 | die("Give the full base uri as a second argument. We'll append a forward slash ourselves."); 34 | } 35 | 36 | var type = "turtle"; 37 | if (process.argv[4] && ['jsonld','turtle','ntriples'].indexOf(process.argv[4]) !== -1 ) { 38 | type = process.argv[4]; 39 | } 40 | 41 | if (!fs.existsSync(path)) { 42 | die(path + " not found"); 43 | } 44 | 45 | //get the feedname: the name of the zip file 46 | if (/(.*\/)?(.*?)\.zip/.exec(path)) { 47 | var feedname = /(.*\/)?(.*?)\.zip/.exec(path)[2]; 48 | } else { 49 | die ("Not a zipfile: " + path); 50 | } 51 | 52 | //create the writer of turtle file towards stdout 53 | var prefixes = { 'gtfs': 'http://vocab.gtfs.org/terms#', 54 | 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 55 | 'foaf' : 'http://xmlns.com/foaf/0.1/', 56 | 'dct' : 'http://purl.org/dc/terms/', 57 | 'rdfs' : 'http://www.w3.org/2000/01/rdf-schema#', 58 | 'owl' : 'http://www.w3.org/2002/07/owl#', 59 | 'xsd' : 'http://www.w3.org/2001/XMLSchema#', 60 | 'vann' : 'http://purl.org/vocab/vann/', 61 | 'skos' : 'http://www.w3.org/2004/02/skos/core#', 62 | 'schema' : "http://schema.org/", 63 | 'dcat' : 'http://www.w3.org/ns/dcat#'}; 64 | 65 | var streamWriter; 66 | 67 | if (type === "jsonld") { 68 | streamWriter = new TriplesToJSONLDStream(); 69 | streamWriter.pipe(new JSONLDSerializer()).pipe(process.stdout); 70 | } else if (type === "ntriples") { 71 | streamWriter = new N3.StreamWriter({format: 'N-Triples'}); 72 | streamWriter.pipe(process.stdout); 73 | } else { 74 | streamWriter = new N3.StreamWriter({prefixes: prefixes}); 75 | streamWriter.pipe(process.stdout); 76 | } 77 | 78 | 79 | mapper(fs.createReadStream(path), streamWriter, { 80 | feedname: feedname, 81 | version : version, 82 | baseuri : baseuri 83 | }); 84 | -------------------------------------------------------------------------------- /lib/transformers/TripsTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(TripsTransformer, Transform); 8 | 9 | function TripsTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | TripsTransformer.prototype._transform = function (data, encoding, done) { 16 | var subject = this._feedbaseuri + "/trips/" + data["trip_id"]; 17 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Trip"}); 18 | 19 | if (data["route_id"]) { 20 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#route", object: this._feedbaseuri + "/routes/" + data["route_id"]}); 21 | } 22 | if (data["service_id"]) { 23 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#service", object: this._feedbaseuri + "/services/" + data["service_id"]}); 24 | } 25 | if (data["trip_headsign"]) { 26 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#headsign", object: '"' + data["trip_headsign"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 27 | } 28 | if (data["trip_short_name"]) { 29 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#shortName", object: '"' + data["trip_short_name"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 30 | } 31 | if (data["direction_id"]) { 32 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#direction", object: (data["direction_id"] === "1"?"\"true\"":"\"false\"") + '^^http://www.w3.org/2001/XMLSchema#boolean'}); 33 | } 34 | if (data["block_id"]) { 35 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#block", object: '"' + data["block_id"] + '"'}); 36 | } 37 | if (data["shape_id"]) { 38 | this.push({ subject: this._feedbaseuri + "/shapes/" + data["shape_id"], predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Shape"}); 39 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#shape", object: this._feedbaseuri + "/shapes/" + data["shape_id"]}); 40 | } 41 | if (data["wheelchair_accessible"]) { 42 | if (data["wheelchair_accessible"] === "0") { 43 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#wheelchairAccessible", object: "http://vocab.gtfs.org/terms#CheckParentStation"}); 44 | } else if (data["wheelchair_accessible"] === "1") { 45 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#wheelchairAccessible", object: "http://vocab.gtfs.org/terms#WheelchairAccessible"}); 46 | } else if (data["wheelchair_accessible"] === "2") { 47 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#wheelchairAccessible", object: "http://vocab.gtfs.org/terms#NotWheelchairAccessible"}); 48 | } 49 | } 50 | if (data["bikes_allowed"]) { 51 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#bikesAllowed", object: (data["bikes_allowed"] == 1 ? "\"true\"": "\"false\"") + '^^http://www.w3.org/2001/XMLSchema#boolean' }); 52 | } 53 | done(); 54 | }; 55 | 56 | module.exports = TripsTransformer; 57 | -------------------------------------------------------------------------------- /lib/transformers/CalendarTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'), 6 | moment = require('moment'); 7 | 8 | util.inherits(CalendarTransformer, Transform); 9 | 10 | function CalendarTransformer (options) { 11 | this._feedbaseuri = options.baseuri; 12 | this._options = options; 13 | Transform.call(this, {objectMode : true}); 14 | } 15 | 16 | CalendarTransformer.prototype._transform = function (data, encoding, done) { 17 | var subject = this._feedbaseuri + "/services/" + data["service_id"]; 18 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Service"}); 19 | var servicerule = subject + "/servicesrules/calendarrule"; 20 | this.push({ subject: servicerule, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#ServiceRule"}); 21 | this.push({ subject: servicerule, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#CalendarRule"}); 22 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#serviceRule", object: servicerule}); 23 | 24 | if (data["monday"]) { 25 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#monday", object: ( data["monday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 26 | } 27 | if (data["tuesday"]) { 28 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#tuesday", object: ( data["tueday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 29 | } 30 | if (data["wednesday"]) { 31 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#wednesday", object: ( data["wednesday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 32 | } 33 | if (data["thursday"]) { 34 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#thursday", object: ( data["thursday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 35 | } 36 | if (data["friday"]) { 37 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#friday", object: ( data["friday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 38 | } 39 | if (data["saturday"]) { 40 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#saturday", object: ( data["saturday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 41 | } 42 | if (data["sunday"]) { 43 | this.push({ subject: servicerule, predicate: "http://vocab.gtfs.org/terms#sunday", object: ( data["sunday"] === "1"?"\"true\"":"\"false\"" ) + "^^http://www.w3.org/2001/XMLSchema#boolean"}); 44 | } 45 | if (data["start_date"] && data["end_date"]){ 46 | var temporal = servicerule + "/temporal"; 47 | this.push({ subject: servicerule, predicate: "http://purl.org/dc/terms/temporal", object: temporal}); 48 | this.push({ subject: temporal, predicate: "http://schema.org/startDate", object: '"' + moment(data["start_date"], "YYYYMMDD").format("YYYY-MM-DD") + '"^^http://www.w3.org/2001/XMLSchema#date'}); 49 | this.push({ subject: temporal, predicate: "http://schema.org/endDate", object: '"' + moment(data["end_date"], "YYYYMMDD").format("YYYY-MM-DD") + '"^^http://www.w3.org/2001/XMLSchema#date'}); 50 | } 51 | done(); 52 | }; 53 | 54 | module.exports = CalendarTransformer; 55 | -------------------------------------------------------------------------------- /lib/transformers/FeedInfoTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'), 6 | moment = require('moment'); 7 | 8 | util.inherits(FeedInfoTransformer, Transform); 9 | 10 | function FeedInfoTransformer (options) { 11 | this._feedbaseuri = options.baseuri; 12 | this._options = options; 13 | Transform.call(this, {objectMode : true}); 14 | this._feedcount = 0; 15 | } 16 | 17 | FeedInfoTransformer.prototype._transform = function (data, encoding, done) { 18 | var subject = this._feedbaseuri + "#feed"; 19 | // dct:identifier triple 20 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Feed"}); 21 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://www.w3.org/ns/dcat#Dataset"}); 22 | this.push({ subject: subject, predicate: "http://purl.org/dc/terms/publisher", object: "_:b" + this._feedcount}); //this is a blank node: we're not sure what URI the publisher has, but we know this URI has a foaf:page and a foaf:name 23 | if (data["feed_publisher_name"]) { 24 | this.push({subject: "_:b" + this._feedcount,predicate: "http://xmlns.com/foaf/0.1/name" , object: '"' + data["feed_publisher_name"] + '"'}); 25 | } 26 | if (data["feed_publisher_url"]) { 27 | this.push({subject: "_:b" + this._feedcount,predicate: "http://xmlns.com/foaf/0.1/page" , object: data["feed_publisher_url"]}); 28 | } 29 | if (data["feed_lang"]) { 30 | //todo: change this into a URI 31 | this.push({ subject: subject, predicate: "http://purl.org/dc/terms/language", object: '"' + data["feed_lang"] + '"'}); 32 | } 33 | if (data["feed_start_date"] && data["feed_end_date"]) { 34 | var temporal = this._feedbaseuri + "/timespan"; 35 | this.push({ subject: subject, predicate: "http://purl.org/dc/terms/temporal", object: temporal}); 36 | this.push({ subject: temporal, predicate: "http://schema.org/startDate", object: '"' + moment(data["feed_start_date"], "YYYYMMDD").format("YYYY-MM-DD") + '"^^http://www.w3.org/2001/XMLSchema#date'}); 37 | this.push({ subject: temporal, predicate: "http://schema.org/endDate", object: '"' + moment(data["feed_end_date"], "YYYYMMDD").format("YYYY-MM-DD") + '"^^http://www.w3.org/2001/XMLSchema#date'}); 38 | } 39 | if (data["feed_version"]) { 40 | this.push({ subject: subject, predicate: "http://schema.org/version", object: '"' + data["feed_version"] + '"'}); 41 | } else { 42 | this.push({ subject: subject, predicate: "http://schema.org/version", object: '"' + this._options.version +'"'}); 43 | } 44 | //has Distribution 1: the path towards the zip 45 | 46 | //TODO: use the URI of the download location, and not a hash 47 | var zipsubject = this._feedbaseuri + "#zip"; 48 | this.push({ subject: zipsubject , predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://www.w3.org/ns/dcat#Distribution" }); 49 | this.push({ subject: zipsubject , predicate: "http://www.w3.org/ns/dcat#mediaType", object: '"'+ "application/zip"+'"' }); 50 | //TODO ... 51 | //has Distribution 2: the path towards the Linked Data Fragments startfragment 52 | var ldfsubject = "http://data.gtfs.org/triples/all"; 53 | this.push({ subject: ldfsubject , predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://www.w3.org/ns/dcat#Distribution" }); 54 | this.push({ subject: ldfsubject , predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://rdfs.org/ns/void#Dataset" }); 55 | 56 | this._feedcount ++; 57 | done(); 58 | }; 59 | 60 | module.exports = FeedInfoTransformer; 61 | -------------------------------------------------------------------------------- /lib/transformers/RoutesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(RoutesTransformer, Transform); 8 | 9 | function RoutesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | RoutesTransformer.prototype._transform = function (data, encoding, done) { 16 | var subject = this._feedbaseuri + "/routes/" + data["route_id"]; 17 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Route"}); 18 | if (data["agency_id"]) { 19 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#agency", object: this._feedbaseuri + "/agencies/" + data["agency_id"]}); 20 | } 21 | if (data["route_short_name"]) { 22 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#shortName", object: '"' + data["route_short_name"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 23 | } 24 | if (data["route_long_name"]) { 25 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#longName", object: '"' + data["route_long_name"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 26 | } 27 | if (data["route_desc"]) { 28 | this.push({ subject: subject, predicate: "http://purl.org/dc/terms/description", object: '"' + data["route_desc"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 29 | } 30 | if (data["route_type"]) { 31 | if (data["route_type"] === "0") { 32 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#LightRail"}); 33 | } else if (data["route_type"] === "1") { 34 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#SubWay"}); 35 | } else if (data["route_type"] === "2") { 36 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#Rail"}); 37 | } else if (data["route_type"] === "3") { 38 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#Bus"}); 39 | } else if (data["route_type"] === "4") { 40 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#Ferry"}); 41 | } else if (data["route_type"] === "5") { 42 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#CableCar"}); 43 | } else if (data["route_type"] === "6") { 44 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#Gondola"}); 45 | } else if (data["route_type"] === "7") { 46 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#routeType", object: "http://vocab.gtfs.org/terms#Funicular"}); 47 | } 48 | } 49 | if (data["route_url"] ) { 50 | this.push({ subject: subject, predicate: "http://xmlns.com/foaf/0.1/page", object : data["route_url"] }); 51 | } 52 | if (data["route_color"] ) { 53 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#color", object : '"' + data["route_color"]+'"^^http://www.w3.org/2001/XMLSchema#string' }); 54 | } 55 | if (data["route_textColor"] ) { 56 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#textColor", object: '"' + data["route_textColor"] + '"^^http://www.w3.org/2001/XMLSchema#string' }); 57 | } 58 | 59 | done(); 60 | }; 61 | 62 | module.exports = RoutesTransformer; 63 | -------------------------------------------------------------------------------- /lib/transformers/StopsTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(StopsTransformer, Transform); 8 | 9 | function StopsTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | /** 16 | * Creates a gtfs:Station or gtfs:Stop with additional properties. Also creates a gtfs:Zone 17 | */ 18 | StopsTransformer.prototype._transform = function (data, encoding, done) { 19 | var subject = this._feedbaseuri + "/stops/" + data["stop_id"]; 20 | this.push({ subject: subject, predicate: "http://purl.org/dc/terms/identifier", object :'"' + data["stop_id"]+'"' }); 21 | // gtfs:locationType triple 22 | if (data["location_type"] && data["location_type"] === "1") { 23 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Station"}); 24 | } else { 25 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#Stop"}); 26 | //Stations can't have a parent_station, only Stops can have a parent station. 27 | if (data["parent_station"]) { 28 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#parentStation", object :'"' + data["parent_station"]+'"' }); 29 | } 30 | if (data["zone_id"]) { 31 | this.push({ subject: this._feedbaseuri + "/zones/" + data["zone_id"], predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object : "http://vocab.gtfs.org/terms#Zone" }); 32 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#zone", object : this._feedbaseuri + "/zones/" + data["zone_id"] }); 33 | } 34 | } 35 | // gtfs:code triple 36 | if (data["stop_code"]) { 37 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#code", object :'"' + data["stop_code"]+'"' }); 38 | } 39 | 40 | // foaf:name triple 41 | if (data["stop_name"]) { 42 | this.push({ subject: subject, predicate: "http://xmlns.com/foaf/0.1/name", object :'"' + data["stop_name"]+'"' }); 43 | } 44 | if (data["stop_desc"]) { 45 | this.push({ subject: subject, predicate: "http://purl.org/dc/terms/description", object :'"' + data["stop_desc"]+'"' }); 46 | } 47 | // geo:lat triple 48 | if (data["stop_lat"]) { 49 | this.push({ subject: subject, predicate: "http://www.w3.org/2003/01/geo/wgs84_pos#lat", object :'"' + data["stop_lat"] + '"' }); 50 | } 51 | // geo:long triple 52 | if (data["stop_lon"]) { 53 | this.push({ subject: subject, predicate: "http://www.w3.org/2003/01/geo/wgs84_pos#long", object :'"' + data["stop_lon"] + '"' }); 54 | } 55 | if (data["stop_url"]) { 56 | this.push({ subject: subject, predicate: "http://xmlns.com/foaf/0.1/page", object : data["stop_url"] }); 57 | } 58 | if (data["wheelchair_boarding"]) { 59 | if (data["wheelchair_boarding"] === "0") { 60 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#wheelchairAccessible", object: "http://vocab.gtfs.org/terms#CheckParentStation"}); 61 | } else if (data["wheelchair_boarding"] === "1") { 62 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#wheelchairAccessible", object : "http://vocab.gtfs.org/terms#WheelchairAccessible" }); 63 | } else if (data["wheelchair_boarding"] === "2") { 64 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#wheelchairAccessible", object : "http://vocab.gtfs.org/terms#NotWheelchairAccessible" }); 65 | } 66 | } 67 | done(); 68 | }; 69 | 70 | module.exports = StopsTransformer; 71 | -------------------------------------------------------------------------------- /lib/transformers/StopTimesTransformer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Pieter Colpaert 3 | */ 4 | var Transform = require('stream').Transform, 5 | util = require('util'); 6 | 7 | util.inherits(StopTimesTransformer, Transform); 8 | 9 | function StopTimesTransformer (options) { 10 | this._feedbaseuri = options.baseuri; 11 | this._options = options; 12 | Transform.call(this, {objectMode : true}); 13 | } 14 | 15 | StopTimesTransformer.prototype._transform = function (data, encoding, done) { 16 | var subject = this._feedbaseuri + "/trip/" + data["trip_id"] + "/stop/" + data["stop_id"]; 17 | this.push({ subject: subject, predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", object: "http://vocab.gtfs.org/terms#StopTime"}); 18 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#stop", object: this._feedbaseuri + "/stops/" + data["stop_id"]}); 19 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#trip", object: this._feedbaseuri + "/trips/" + data["trip_id"]}); 20 | if (data["arrival_time"]){ 21 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#arrivalTime", object: '"' + data["arrival_time"] + '"^^http://www.w3.org/2001/XMLSchema#duration'}); 22 | } 23 | if (data["departure_time"]){ 24 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#departureTime", object: '"' + data["departure_time"] + '"^^http://www.w3.org/2001/XMLSchema#duration'}); 25 | } 26 | if (data["stop_sequence"]){ 27 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#stopSequence", object: '"' + data["stop_sequence"] + '"^^http://www.w3.org/2001/XMLSchema#nonNegativeInteger'}); 28 | } 29 | if (data["stop_headsign"]){ 30 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#headsign", object: '"' + data["stop_headsign"] + '"^^http://www.w3.org/2001/XMLSchema#string'}); 31 | } 32 | if (data["pickup_type"]){ 33 | if (data["pickup_type"] === "0") { 34 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#pickupType", object: "http://vocab.gtfs.org/terms#Regular"}); 35 | } else if (data["pickup_type"] === "1") { 36 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#pickupType", object: "http://vocab.gtfs.org/terms#NotAvailable"}); 37 | } else if (data["pickup_type"] === "2") { 38 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#pickupType", object: "http://vocab.gtfs.org/terms#MustPhone"}); 39 | } else if (data["pickup_type"] === "3") { 40 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#pickupType", object: "http://vocab.gtfs.org/terms#MustCoordinateWithDriver"}); 41 | } 42 | } 43 | if (data["drop_off_type"]){ 44 | if (data["drop_off_type"] === "0") { 45 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#dropOffType", object: "http://vocab.gtfs.org/terms#Regular"}); 46 | } else if (data["drop_off_type"] === "1") { 47 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#dropOffType", object: "http://vocab.gtfs.org/terms#NotAvailable"}); 48 | } else if (data["drop_off_type"] === "2") { 49 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#dropOffType", object: "http://vocab.gtfs.org/terms#MustPhone"}); 50 | } else if (data["drop_off_type"] === "3") { 51 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#dropOffType", object: "http://vocab.gtfs.org/terms#MustCoordinateWithDriver"}); 52 | } 53 | } 54 | if (data["shape_dist_traveled"]){ 55 | this.push({ subject: subject, predicate: "http://vocab.gtfs.org/terms#distanceTraveled", object: '"' + data["shape_dist_traveled"] + '"^^http://www.w3.org/2001/XMLSchema#nonNegativeInteger'}); 56 | } 57 | done(); 58 | }; 59 | 60 | module.exports = StopTimesTransformer; 61 | --------------------------------------------------------------------------------