<?php | <?php |
include('common.inc.php'); | include('common.inc.php'); |
include_header("Routes"); | include_header("Routes"); |
echo' | echo' |
<div data-role="navbar"> | <div data-role="navbar"> |
<ul> | <ul> |
<li><a href="routeList.php">By Final Destination...</a></li> | <li><a href="routeList.php">By Final Destination...</a></li> |
<li><a href="routeList.php?bynumber=yes">By Number... </a></li> | <li><a href="routeList.php?bynumber=yes">By Number... </a></li> |
<!--<li><a href="routeList.php?bysuburb=yes">By Suburb... </a></li>--> | <!--<li><a href="routeList.php?bysuburb=yes">By Suburb... </a></li>--> |
</ul> | </ul> |
</div> | </div> |
'; | '; |
echo ' <ul data-role="listview">'; | echo ' <ul data-role="listview">'; |
$url = $APIurl."/json/routes"; | $url = $APIurl."/json/routes"; |
$contents = json_decode(getPage($url)); | $contents = json_decode(getPage($url)); |
debug(print_r($contents,true)); | debug(print_r($contents,true)); |
function printRoutes($routes){ | function printRoutes($routes){ |
foreach($routes as $row) { | foreach($routes as $row) { |
echo '<li>'.$row[1].' <a href="trip.php?routeid='.$row[0].'">'.$row[2]." (".ucwords($row[3]).")</a></li>\n"; | echo '<li>'.$row[1].' <a href="trip.php?routeid='.$row[0].'">'.$row[2]." (".ucwords($row[3]).")</a></li>\n"; |
} | } |
} | } |
if ($_REQUEST['bynumber']) { | if ($_REQUEST['bynumber']) { |
$routeSeries = Array(); | $routeSeries = Array(); |
$seriesRange = Array(); | $seriesRange = Array(); |
foreach ($contents as $key => $row) { | foreach ($contents as $key => $row) { |
foreach (explode(" ",$row[1]) as $routeNumber ) { | foreach (explode(" ",$row[1]) as $routeNumber ) { |
$seriesNum = substr($routeNumber, 0, -1)."0"; | $seriesNum = substr($routeNumber, 0, -1)."0"; |
if ($seriesNum == "0") $seriesNum = $routeNumber; | if ($seriesNum == "0") $seriesNum = $routeNumber; |
$finalDigit = substr($routeNumber, sizeof($routeNumber)-1, 1); | $finalDigit = substr($routeNumber, sizeof($routeNumber)-1, 1); |
if (isset($seriesRange[$seriesNum])) { | if (isset($seriesRange[$seriesNum])) { |
if ($finalDigit < $seriesRange[$seriesNum]['max']) | if ($finalDigit < $seriesRange[$seriesNum]['max']) |
$seriesRange[$seriesNum]['max'] = $routeNumber; | $seriesRange[$seriesNum]['max'] = $routeNumber; |
if ($finalDigit > $seriesRange[$seriesNum]['min']) | if ($finalDigit > $seriesRange[$seriesNum]['min']) |
$seriesRange[$seriesNum]['min'] = $routeNumber; | $seriesRange[$seriesNum]['min'] = $routeNumber; |
} else { | } else { |
$seriesRange[$seriesNum]['max'] = $routeNumber; | $seriesRange[$seriesNum]['max'] = $routeNumber; |
$seriesRange[$seriesNum]['min'] = $routeNumber; | $seriesRange[$seriesNum]['min'] = $routeNumber; |
} | } |
$routeSeries[$seriesNum][$seriesNum."-".$row[1]."-".$row[0]] = $row; | $routeSeries[$seriesNum][$seriesNum."-".$row[1]."-".$row[0]] = $row; |
} | } |
} | } |
ksort($routeSeries); | ksort($routeSeries); |
ksort($seriesRange); | ksort($seriesRange); |
echo '<div class="noscriptnav"> Go to route numbers: '; | echo '<div class="noscriptnav"> Go to route numbers: '; |
foreach ($seriesRange as $series => $range) | foreach ($seriesRange as $series => $range) |
{ | { |
if ($range['min'] == $range['max']) echo "<a href=\"#$series\">$series</a> "; | if ($range['min'] == $range['max']) echo "<a href=\"#$series\">$series</a> "; |
else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a> "; | else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a> "; |
} | } |
echo "</div> | echo "</div> |
<script> | <script> |
$('.noscriptnav').hide(); | $('.noscriptnav').hide(); |
</script>"; | </script>"; |
foreach ($routeSeries as $series => $routes) | foreach ($routeSeries as $series => $routes) |
{ | { |
echo '<a name="'.$series.'"></a>'; | echo '<a name="'.$series.'"></a>'; |
if ($series <= 9) echo '<li>'.$series."<ul>\n"; | if ($series <= 9) echo '<li>'.$series."<ul>\n"; |
else echo "<li>{$seriesRange[$series]['min']}-{$seriesRange[$series]['max']}<ul>\n"; | else echo "<li>{$seriesRange[$series]['min']}-{$seriesRange[$series]['max']}<ul>\n"; |
printRoutes($routes); | printRoutes($routes); |
echo "</ul></li>\n"; | echo "</ul></li>\n"; |
} | } |
} else { | } else { |
foreach ($contents as $key => $row) { | foreach ($contents as $key => $row) { |
$routeDestinations[$row[2]][] = $row; | $routeDestinations[$row[2]][] = $row; |
} | } |
echo '<div class="noscriptnav"> Go to Destination: '; | echo '<div class="noscriptnav"> Go to Destination: '; |
foreach($routeDestinations as $destination => $routes) | foreach(ksort($routeDestinations) as $destination => $routes) |
{ | { |
echo "<a href=\"#$destination\">$destination</a> "; | echo "<a href=\"#$destination\">$destination</a> "; |
} | } |
echo "</div> | echo "</div> |
<script> | <script> |
$('.noscriptnav').hide(); | $('.noscriptnav').hide(); |
</script>"; | </script>"; |
foreach ($routeDestinations as $destination => $routes) | foreach ($routeDestinations as $destination => $routes) |
{ | { |
echo '<a name="'.$destination.'"></a>'; | echo '<a name="'.$destination.'"></a>'; |
echo '<li>'.$destination."... <ul>\n"; | echo '<li>'.$destination."... <ul>\n"; |
printRoutes($routes); | printRoutes($routes); |
echo "</ul></li>\n"; | echo "</ul></li>\n"; |
} | } |
} | } |
echo "</ul>\n"; | echo "</ul>\n"; |
include_footer(); | include_footer(); |
?> | ?> |
require 'rubygems' | require 'rubygems' |
require 'nokogiri' | require 'nokogiri' |
require 'open-uri' | require 'open-uri' |
require 'pp' | require 'pp' |
require 'yaml' | require 'yaml' |
class Array | class Array |
def to_yaml_style | def to_yaml_style |
:inline | :inline |
end | end |
end | end |
def makeTimetable(table, period, short_name) | def makeTimetable(table, period, short_name) |
timetable = {"between_stops" => [], "short_name" => short_name} | timetable = {"between_stops" => [], "short_name" => short_name} |
time_points = table.xpath('tr[1]//th').map do |tp| | time_points = table.xpath('tr[1]//th').map do |tp| |
if tp.content != "\302\240" && tp.content != "" && tp.content != "<br/>" | if tp.content != "\302\240" && tp.content != "" && tp.content != "<br/>" |
timing_point = tp.content.squeeze(" ").gsub("Shops"," ").gsub("Bus Station"," Bus Station ").gsub(" Platform"," (Platform").gsub(" - "," - ").gsub("\n"," ").gsub("\r"," ").gsub("\t"," ").gsub("\\"," / ").gsub("/"," / ").gsub(","," ").gsub("\302\240","").squeeze(" ").strip | timing_point = tp.content.squeeze(" ").gsub("Shops"," ").gsub("Bus Station"," Bus Station ").gsub("Interchange"," Bus Station ").gsub(" Platform"," (Platform") |
timing_point = timing_point.gsub("Machonochie","Maconochie").gsub("Hume"," ").gsub("Market Place","Marketplace").gsub("Terminus Fyshwick","Terminus") | |
timing_point = timing_point.gsub(" - "," - ").gsub("\n"," ").gsub("\r"," ").gsub("\t"," ").gsub("\\"," / ").gsub("/"," / ").gsub(","," ").gsub("\302\240","").squeeze(" ").strip | |
if (tp.content.match('Platform')) | if (tp.content.match('Platform')) |
timing_point.concat(")") | timing_point.concat(")") |
end; | end; |
if tp.to_s.match(/[0-9][0-9][0-9]/) or tp.to_s.include? "Wheelchair" | if tp.to_s.match(/[0-9][0-9][0-9]/) or tp.to_s.include? "Wheelchair" |
timing_point = nil | timing_point = nil |
end | end |
timing_point | timing_point |
end | end |
end | end |
time_points.delete(nil) | time_points.delete(nil) |
timetable["time_points"] = time_points.to_a | timetable["time_points"] = time_points.to_a |
timetable["long_name"] = "To " + time_points.last | timetable["long_name"] = "To " + time_points.last |
periodtimes = [] | periodtimes = [] |
table.css('tr').each do |row| | table.css('tr').each do |row| |
times = row.css('td').map do |cell| | times = row.css('td').map do |cell| |
time = cell.content.squeeze(" ").strip | time = cell.content.squeeze(" ").strip |
time = time.gsub(/ *A\S?M/,"a").gsub(/ ?P\S?M/,"p").gsub(/ *a\S?m/,"a").gsub(/ ?p\S?m/,"p") | time = time.gsub(/ *A\S?M/,"a").gsub(/ ?P\S?M/,"p").gsub(/ *a\S?m/,"a").gsub(/ ?p\S?m/,"p") |
time = time.gsub("12:08 AM","1208x").gsub(":","").gsub("1.","1").gsub("2.","2").gsub("3.","3").gsub("4.","4") | time = time.gsub("12:08 AM","1208x").gsub(":","").gsub("1.","1").gsub("2.","2").gsub("3.","3").gsub("4.","4") |
time = time.gsub("5.","5").gsub("6.","6").gsub("7.","7").gsub("8.","8").gsub("9.","9").gsub("10.","10") | time = time.gsub("5.","5").gsub("6.","6").gsub("7.","7").gsub("8.","8").gsub("9.","9").gsub("10.","10") |
time = time.gsub("11.","11").gsub("12.","12").gsub(/\.+/,"-").gsub("\302\240","") | time = time.gsub("11.","11").gsub("12.","12").gsub(/\.+/,"-").gsub("\302\240","") |
if time == "" or time.include? "chool" or time.include? "On Race Days" or time.include? "Bus" | if time == "" or time.include? "chool" or time.include? "On Race Days" or time.include? "Bus" |
time = nil # This hacky way is faster than using position()>1 xpath on <TD>s! | time = nil # This hacky way is faster than using position()>1 xpath on <TD>s! |
end | end |
time | time |
end | end |
times.delete(nil) | times.delete(nil) |
if not times.empty? | if not times.empty? |
if not (route = times.shift) | if not (route = times.shift) |
raise("TODO: account for shifting route numbers eg. intertown/redex 62/162") | raise("TODO: account for shifting route numbers eg. intertown/redex 62/162") |
end | end |
periodtimes << times.to_a | periodtimes << times.to_a |
end | end |
end | end |
if periodtimes.size < 1 | if periodtimes.size < 1 |
raise "No times for route " + short_name + " in period " + period | raise "No times for route " + short_name + " in period " + period |
end | end |
timetable[period] = periodtimes.to_a | timetable[period] = periodtimes.to_a |
# pp timetable | # pp timetable |
filename = timetable["short_name"] + "-" + timetable["long_name"]+ "." + period + ".yml" | filename = timetable["short_name"] + "-" + timetable["long_name"]+ "." + period + ".yml" |
filename = filename.downcase.gsub(" ","-").gsub("/","-").gsub("(","").gsub(")","") | filename = filename.downcase.gsub(" ","-").gsub("/","-").gsub("(","").gsub(")","") |
puts "Saving " + filename | puts "Saving " + filename |
File.open("#{File.dirname(__FILE__)}/output/"+filename, "w") do |f| | File.open("#{File.dirname(__FILE__)}/output/"+filename, "w") do |f| |
f.write timetable.to_yaml | f.write timetable.to_yaml |
end | end |
timetable | timetable |
end | end |
Dir.glob("source-html/*oute*.htm*") { |file| | Dir.glob("source-html/*oute*.htm*") { |file| |
puts "Opened " + file | puts "Opened " + file |
doc = Nokogiri::HTML(open(file)) | doc = Nokogiri::HTML(open(file)) |
# Search for nodes by css | # Search for nodes by css |
timetables = [] | timetables = [] |
short_name = ""; | short_name = ""; |
doc.xpath('//title').each do |title| | doc.xpath('//title').each do |title| |
short_name = title.content.gsub("Route_","").gsub("Route ","").gsub("route ","").gsub(", ","/").gsub("ACTION Buses Timetable for ","").squeeze(" ").strip | short_name = title.content.gsub("Route_","").gsub("Route ","").gsub("route ","").gsub(", ","/").gsub("ACTION Buses Timetable for ","").squeeze(" ").strip |
end | end |
if short_name == "" | if short_name == "" |
raise "Route number(s) not found in <title> tag" | raise "Route number(s) not found in <title> tag" |
end | end |
doc.xpath('//table[preceding::text()="Weekdays"]').each do |table| | doc.xpath('//table[preceding::text()="Weekdays"]').each do |table| |
timetables << makeTimetable(table, "stop_times", short_name) | timetables << makeTimetable(table, "stop_times", short_name) |
end | end |
doc.xpath('//table[preceding::text()="This timetable is effective from Monday 15th November 2010."]').each do |table| | doc.xpath('//table[preceding::text()="This timetable is effective from Monday 15th November 2010."]').each do |table| |
if short_name[0].chr != "9" or short_name.size == 1 | if short_name[0].chr != "9" or short_name.size == 1 |
timetables << makeTimetable(table, "stop_times", short_name) | timetables << makeTimetable(table, "stop_times", short_name) |
end | end |
end | end |
#all tables are weekdays on some really malformatted timetables | #all tables are weekdays on some really malformatted timetables |
if short_name == "170" | if short_name == "170" |
doc.xpath('//table').each do |table| | doc.xpath('//table').each do |table| |
timetables << makeTimetable(table, "stop_times", short_name) | timetables << makeTimetable(table, "stop_times", short_name) |
end | end |
end | end |
#weekends | #weekends |
doc.xpath('//table[preceding::text()="Saturdays" and following::a]').each do |table| | doc.xpath('//table[preceding::text()="Saturdays" and following::a]').each do |table| |
timetables << makeTimetable(table, "stop_times_saturday", short_name) | timetables << makeTimetable(table, "stop_times_saturday", short_name) |
end | end |
doc.xpath('//table[preceding::text()="Sundays"]').each do |table| | doc.xpath('//table[preceding::text()="Sundays"]').each do |table| |
timetables << makeTimetable(table, "stop_times_sunday", short_name) | timetables << makeTimetable(table, "stop_times_sunday", short_name) |
end | end |
#930/934 special cases | #930/934 special cases |
doc.xpath('//table[preceding::text()="Saturday" and following::h2]').each do |table| | doc.xpath('//table[preceding::text()="Saturday" and following::h2]').each do |table| |
timetables << makeTimetable(table, "stop_times_saturday", short_name) | timetables << makeTimetable(table, "stop_times_saturday", short_name) |
end | end |
doc.xpath('//table[preceding::text()="Sunday"]').each do |table| | doc.xpath('//table[preceding::text()="Sunday"]').each do |table| |
timetables << makeTimetable(table, "stop_times_sunday", short_name) | timetables << makeTimetable(table, "stop_times_sunday", short_name) |
end | end |
#route 81 = Weekdays - School Holidays Only | #route 81 = Weekdays - School Holidays Only |
doc.xpath('//table[preceding::text()="Weekdays - School Holidays Only "]').each do |table| | doc.xpath('//table[preceding::text()="Weekdays - School Holidays Only "]').each do |table| |
timetable = makeTimetable(table, "stop_times", short_name) | timetable = makeTimetable(table, "stop_times", short_name) |
#TODO set active date range to only be holidays | #TODO set active date range to only be holidays |
timetables << timetable; | timetables << timetable; |
end | end |
if timetables.size > 2 | if timetables.size > 2 |
puts "WARNING: " + file + " more than 2 timetables (weekend split?):" + timetables.size.to_s | puts "WARNING: " + file + " more than 2 timetables (weekend split?):" + timetables.size.to_s |
end | end |
if timetables.size < 2 | if timetables.size < 2 |
puts "WARNING: " + file + " less than 2 timetables (weekday loop service?):" + timetables.size.to_s | puts "WARNING: " + file + " less than 2 timetables (weekday loop service?):" + timetables.size.to_s |
elsif not (timetables[0]["time_points"] - timetables[1]["time_points"].reverse).empty? | elsif not (timetables[0]["time_points"] - timetables[1]["time_points"].reverse).empty? |
puts "WARNING: first pair of timetable timing points are not complementary for "+ file | puts "WARNING: first pair of timetable timing points are not complementary for "+ file |
pp(timetables[0]["time_points"] - timetables[1]["time_points"].reverse) | pp(timetables[0]["time_points"] - timetables[1]["time_points"].reverse) |
end | end |
if timetables.size < 1 | if timetables.size < 1 |
raise "No timetables extracted from " + file | raise "No timetables extracted from " + file |
end | end |
} | } |
options: | options: |
start_date: 20101115 | start_date: 20101115 |
end_date: 20111231 | end_date: 20111231 |
remove_date: 20111231 | remove_date: 20111231 |
agency_name: ACT Internal Omnibus Network (ACTION) | agency_name: ACT Internal Omnibus Network (ACTION) |
agency_url: http://www.action.act.gov.au/ | agency_url: http://www.action.act.gov.au/ |
agency_timezone: Australia/Sydney | agency_timezone: Australia/Sydney |
stops: | stops: |
- { name: ACTEW AGL House,stop_code: ACTEW AGL House, lat: -35.282374, lng: 149.132047} | - { name: ACTEW AGL House,stop_code: ACTEW AGL House, lat: -35.282374, lng: 149.132047} |
- { name: ADFA,stop_code: ADFA, lat: -35.2937972, lng: 149.1643403} | - { name: ADFA,stop_code: ADFA, lat: -35.2937972, lng: 149.1643403} |
- { name: Ainslie,stop_code: Ainslie, lat: -35.2620105, lng: 149.1443302} | - { name: Ainslie,stop_code: Ainslie, lat: -35.2620105, lng: 149.1443302} |
- { name: Alexander Maconochie Centre,stop_code: Alexander Maconochie Centre, lat: -35.3720651, lng: 149.1696618} | - { name: Alexander Maconochie Centre,stop_code: Alexander Maconochie Centre, lat: -35.3720651, lng: 149.1696618} |
- { name: Alpen & Clifford St,stop_code: Alpen & Clifford St, lat: -35.20562, lng: 149.06259} | - { name: Alpen & Clifford St,stop_code: Alpen & Clifford St, lat: -35.20562, lng: 149.06259} |
- { name: Anthony Rolfe Av / Moonlight Av,stop_code: Anthony Rolfe Av / Moonlight Av, lat: -35.1856021, lng: 149.1543639} | - { name: Anthony Rolfe Av / Moonlight Av,stop_code: Anthony Rolfe Av / Moonlight Av, lat: -35.1856021, lng: 149.1543639} |
- { name: Aranda,stop_code: Aranda, lat: -35.257534, lng: 149.0762963} | - { name: Aranda,stop_code: Aranda, lat: -35.257534, lng: 149.0762963} |
- { name: Athllon / Sulwood Kambah,stop_code: Athllon / Sulwood Kambah, lat: -35.38442, lng: 149.09328} | - { name: Athllon / Sulwood Kambah,stop_code: Athllon / Sulwood Kambah, lat: -35.38442, lng: 149.09328} |
- { name: Australian Institute of Sport,stop_code: Australian Institute of Sport, lat: -35.246351, lng: 149.101478} | - { name: Australian Institute of Sport,stop_code: Australian Institute of Sport, lat: -35.246351, lng: 149.101478} |
- { name: Belconnen Community Bus Station,stop_code: Belconnen Community Bus Station, lat: -35.23987, lng: 149.0619} | - { name: Belconnen Community Bus Station,stop_code: Belconnen Community Bus Station, lat: -35.23987, lng: 149.0619} |
- { name: Belconnen Community Bus Station (Platform 1),stop_code: Belconnen Community Bus Station (Platform 1), lat: -35.23982, lng: 149.06978} | - { name: Belconnen Community Bus Station (Platform 1),stop_code: Belconnen Community Bus Station (Platform 1), lat: -35.23982, lng: 149.06978} |
- { name: Belconnen Community Bus Station (Platform 2),stop_code: Belconnen Community Bus Station (Platform 2), lat: -35.23982, lng: 149.06926} | - { name: Belconnen Community Bus Station (Platform 2),stop_code: Belconnen Community Bus Station (Platform 2), lat: -35.23982, lng: 149.06926} |
- { name: Belconnen Community Bus Station (Platform 3),stop_code: Belconnen Community Bus Station (Platform 3), lat: -35.23986, lng: 149.06847} | - { name: Belconnen Community Bus Station (Platform 3),stop_code: Belconnen Community Bus Station (Platform 3), lat: -35.23986, lng: 149.06847} |
- { name: Belconnen Community Bus Station (Platform 4),stop_code: Belconnen Community Bus Station (Platform 4), lat: -35.23994, lng: 149.06887} | - { name: Belconnen Community Bus Station (Platform 4),stop_code: Belconnen Community Bus Station (Platform 4), lat: -35.23994, lng: 149.06887} |
- { name: Belconnen Community Bus Station (Platform 5),stop_code: Belconnen Community Bus Station (Platform 5), lat: -35.23994, lng: 149.06928} | - { name: Belconnen Community Bus Station (Platform 5),stop_code: Belconnen Community Bus Station (Platform 5), lat: -35.23994, lng: 149.06928} |
- { name: Belconnen Community Bus Station (Platform 6),stop_code: Belconnen Community Bus Station (Platform 6), lat: -35.23994, lng: 149.0698} | - { name: Belconnen Community Bus Station (Platform 6),stop_code: Belconnen Community Bus Station (Platform 6), lat: -35.23994, lng: 149.0698} |
- { name: Belconnen Way,stop_code: Belconnen Way, lat: -35.24809, lng: 149.06765} | - { name: Belconnen Way,stop_code: Belconnen Way, lat: -35.24809, lng: 149.06765} |
- { name: Bimberi Centre,s |