Created
August 16, 2011 12:43
-
-
Save andrewharvey/1148982 to your computer and use it in GitHub Desktop.
XSL to convert http://api.fosm.org/api/0.6/changesets into an Atom/GeoRSS feed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -wT | |
# This script uses XML::Atom::Filter to filter an existing FOSM recent changes | |
# feed given a query bbox based on the georss:box for each entry in the feed | |
# | |
# Ideally we would implement it on the server for /feed to return the static | |
# atom feed from disk, and /feed?bbox to call this CGI script. | |
# | |
# This script is licensed CC0 by Andrew Harvey <[email protected]> | |
# | |
# To the extent possible under law, the person who associated CC0 | |
# with this work has waived all copyright and related or neighboring | |
# rights to this work. | |
# http://creativecommons.org/publicdomain/zero/1.0/ | |
use strict; | |
use CGI; | |
use XML::Atom::Filter; | |
my $cgi = CGI->new; | |
my $cgi_query_bbox = $cgi->param('bbox'); | |
my $cgi_query_left = $cgi->param('left'); | |
my $cgi_query_right = $cgi->param('right'); | |
my $cgi_query_top = $cgi->param('top'); | |
my $cgi_query_bottom = $cgi->param('bottom'); | |
# FIXME: how should we go about implementing a /feed and /feed?bbox api like | |
# OSM? Should we use a fancy proxy in our web server, or adapt this script to | |
# handle /feed without a bbox. Ideally the latter shouldn't add a performance | |
# hit to the former. | |
if (!defined $cgi_query_bbox) { | |
if ((!defined $cgi_query_left) || (!defined $cgi_query_right) || (!defined $cgi_query_top) || (!defined $cgi_query_bottom)) { | |
print $cgi->header(-status => '400', -type => 'text/plain'); | |
print "For now, the endpoint URL for a filtered feed and non-filtered feed are different, so for this URL you must specify a bbox paramater or the left,bottom,right,top paramaters.\n"; | |
exit; | |
} | |
} | |
my $query_bottom; | |
my $query_left; | |
my $query_top; | |
my $query_right; | |
# check bbox syntax | |
if (defined $cgi_query_bbox) { | |
if ($cgi_query_bbox !~ /^([-]?\d+\.?\d*),([-]?\d+\.?\d*),([-]?\d+\.?\d*),([-]?\d+\.?\d*)$/) { | |
print $cgi->header(-status => '400', -type => 'text/plain'); | |
print "Your bbox paramater is malformed.\n"; | |
exit; | |
}else{ | |
# get query bbox from URL parameters | |
$query_bottom = $2; | |
$query_left = $1; | |
$query_top = $4; | |
$query_right = $3; | |
} | |
}else{ | |
if (($cgi_query_left !~ /^([-]?\d+\.?\d*)$/) || | |
($cgi_query_right !~ /^([-]?\d+\.?\d*)$/) || | |
($cgi_query_top !~ /^([-]?\d+\.?\d*)$/) || | |
($cgi_query_bottom !~ /^([-]?\d+\.?\d*)$/)) { | |
print $cgi->header(-status => '400', -type => 'text/plain'); | |
print "Your left,right,top,bottom paramaters are malformed.\n"; | |
exit; | |
}else{ | |
$query_bottom = $cgi_query_bottom; | |
$query_left = $cgi_query_left; | |
$query_top = $cgi_query_top; | |
$query_right = $cgi_query_right; | |
} | |
} | |
my $f = XML::Atom::Filter->new(); | |
my $input_file = "fosm-changesets.atom"; | |
open(my $in_fh, '<', $input_file) or die $!; | |
{ no warnings 'redefine'; | |
# update the feed header to reflect this is a feed for the given bbox | |
sub XML::Atom::Filter::pre { | |
my ($class, $feed) = @_; | |
# retitle the feed | |
# TODO we could instead add area in sq km, and give a close locality but we will keep it simple for now | |
$feed->title($feed->title . " for $query_left,$query_bottom,$query_right,$query_top"); | |
$feed->id($feed->id . "?bbox=$query_left,$query_bottom,$query_right,$query_top"); | |
} | |
# find the extents of this entry from the georss:box element and test if it | |
# overlaps our query bbox | |
sub XML::Atom::Filter::entry { | |
my ($class, $entry) = @_; | |
my $georss_ns = XML::Atom::Namespace->new(dc => 'http://www.georss.org/georss'); | |
my $bbox = $entry->get($georss_ns, 'box'); | |
my ($bottom, $left, $top, $right) = split / /, $bbox; | |
if ($left < $query_right && $right > $query_left && | |
$bottom < $query_top && $top > $query_bottom) { | |
# this entry overlaps our query bbox, so leave it in the output feed | |
return $entry; | |
}else{ | |
# return undef to filter this entry out of the output feed | |
return undef; | |
} | |
} | |
} | |
# return the filtered feed | |
print $cgi->header(-type => 'application/atom+xml; charset=utf-8'); | |
# FIXME how to have this return a pretty printed feed? | |
$f->filter($in_fh); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!-- | |
This XSL stylesheet takes an XML document of recent FOSM.org changesets and | |
produces an Atom feed of those changesets. The output is modeled on the | |
changeset/feed Atom output of http://git.openstreetmap.org/?p=rails.git | |
xsltproc is one such program which can apply this XSL to produce the Atom feed. | |
This document is licensed CC0 by Andrew Harvey. | |
To the extent possible under law, the person who associated CC0 | |
with this work has waived all copyright and related or neighboring | |
rights to this work. | |
http://creativecommons.org/publicdomain/zero/1.0/ | |
--> | |
<xsl:stylesheet | |
version="1.0" | |
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | |
xmlns="http://www.w3.org/2005/Atom" | |
xmlns:georss="http://www.georss.org/georss"> | |
<xsl:output method="xml" indent="yes" encoding="UTF-8"/> | |
<xsl:template match="/osm"> | |
<feed xml:lang="en" xmlns:georss="http://www.georss.org/georss" xmlns="http://www.w3.org/2005/Atom"> | |
<id>http://api.fosm.org/api/0.6/changesets/feed</id> | |
<title>Recent fosm.org Changesets</title> | |
<icon>http://www.openstreetmap.org/favicon.ico</icon> | |
<logo>http://www.openstreetmap.org/images/mag_map-rss2.0.png</logo> | |
<rights type="xhtml"> | |
<div xmlns="http://www.w3.org/1999/xhtml"> | |
<a href="http://creativecommons.org/licenses/by-sa/2.0/"> | |
<img src="http://i.creativecommons.org/l/by-sa/2.0/88x31.png" alt="Creative Commons by-sa 2.0"/> | |
</a> | |
</div> | |
</rights> | |
<link href="http://api.fosm.org/api/0.6/changesets" type="text/xml" rel="alternate"/> | |
<xsl:apply-templates select="changeset"> | |
</xsl:apply-templates> | |
</feed> | |
</xsl:template> | |
<xsl:template match="changeset"> | |
<xsl:param name="id" select="@id"/> | |
<xsl:param name="user" select="@user"/> | |
<entry> | |
<id><xsl:text>http://api.fosm.org/api/0.6/changeset/</xsl:text><xsl:value-of select="@id"/></id> | |
<published><xsl:value-of select="@created_at"/></published> | |
<updated><xsl:value-of select="@closed_at"/></updated> | |
<link type="text/html" href="http://tianjara.net/fosmhv/changeset.jsp?id={$id}" rel="alternate"/> | |
<link href="http://api.fosm.org/api/0.6/changeset/{$id}" type="application/osm+xml" rel="alternate"/> | |
<link href="http://api.fosm.org/api/0.6/changeset/{$id}/download" type="application/osmChange+xml" rel="alternate"/> | |
<title type="html"> | |
<xsl:text>Changeset </xsl:text> | |
<xsl:value-of select="@id"/> | |
<xsl:text> - </xsl:text> | |
<xsl:value-of select="tag[@k='comment']/@v"/> | |
</title> | |
<author> | |
<name><xsl:value-of select="@user"/></name> | |
<uri><xsl:text>http://www.openstreetmap.org/user/</xsl:text><xsl:value-of select="@user"/></uri> | |
</author> | |
<content type="xhtml"> | |
<div xmlns="http://www.w3.org/1999/xhtml"> | |
<style>th { text-align: left } tr { vertical-align: top }</style> | |
<table> | |
<tr> | |
<th>Created at:</th> | |
<td><xsl:value-of select="@created_at"/></td> | |
</tr> | |
<tr> | |
<th>Closed at:</th> | |
<td><xsl:value-of select="@closed_at"/></td> | |
</tr> | |
<tr> | |
<th>Belongs to:</th> | |
<td> | |
<a href="http://www.openstreetmap.org/user/{$user}"><xsl:value-of select="@user"/></a> | |
</td> | |
</tr> | |
<tr> | |
<th>Tags:</th> | |
<td> | |
<table cellpadding="0"> | |
<xsl:apply-templates select="tag"> | |
</xsl:apply-templates> | |
</table> | |
</td> | |
</tr> | |
</table> | |
</div> | |
</content> | |
<georss:box> | |
<xsl:value-of select="@min_lat"/> | |
<xsl:text> </xsl:text> | |
<xsl:value-of select="@min_lon"/> | |
<xsl:text> </xsl:text> | |
<xsl:value-of select="@max_lat"/> | |
<xsl:text> </xsl:text> | |
<xsl:value-of select="@max_lon"/> | |
</georss:box> | |
</entry> | |
</xsl:template> | |
<xsl:template match="tag" xmlns="http://www.w3.org/1999/xhtml"> | |
<tr> | |
<td/> | |
<xsl:value-of select="@k"/> | |
<xsl:text> = </xsl:text> | |
<xsl:value-of select="@v"/> | |
</tr> | |
</xsl:template> | |
</xsl:stylesheet> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# This script is a wrapper around the changesets-osm2atom.xsl script. | |
# It fetches the changeset xml from fosm.org, runs xslt and pushes the | |
# result to the web server document directory. | |
# You can add this script as an hourly cron task for hourly updates. | |
# This script is licensed CC0 http://creativecommons.org/publicdomain/zero/1.0/ | |
TMPDIR=/tmp/fosm-changesets-feed | |
WWWDIR=/var/www | |
mkdir -p $TMPDIR | |
curl -o $TMPDIR/incomming "http://api.fosm.org/api/0.6/changesets" | |
if [ $? -ne 0 ] ; then | |
# raise error | |
echo "curl error $?" | |
exit 1 | |
fi | |
xsltproc -o $TMPDIR/outgoing changesets-osm2atom.xsl $TMPDIR/incomming | |
if [ $? -ne 0 ] ; then | |
# raise error | |
echo "xslt error $?" | |
exit 1 | |
fi | |
sed "s/<rights type=\"xhtml\">/<updated>`date --utc --rfc-3339=seconds | sed 's/ /T/' | sed 's/+.*$/Z/'`<\/updated>\n <rights type=\"xhtml\">/" $TMPDIR/outgoing > $TMPDIR/outgoing-patched | |
cp $TMPDIR/outgoing-patched $WWWDIR/fosm-changesets.atom | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment