[OSM-newbies] XSLT question (solved!)

Andrew Errington a.errington at lancaster.ac.uk
Sat Sep 19 05:31:38 BST 2009


On Wed, September 16, 2009 15:04, Renaud MICHEL wrote:
> If you want to do a sum you must have a node-set, which you can't have
> with key(), so you will need to reference the elements directly (which is
> a lot slower than key() ), like this (the way being the current node)
<snippety snip>

Hi Renaud (and everyone),

It works!  I can now programmatically produce a list of lat/lon pairs for
amenities regardless of whether they are nodes or areas.  If they are
areas then I use Renaud's code to calculate an average lat and average
lon, which produces an adequate centroid.  Actually, if someone can
suggest how to sum (and count) all but the first or last lat/lon pair it
would make the result better, since the first and last pair are identical
(to close the area) they weight the average.

I am pasting the code here as it is so simple.  The output can be used
with the example OpenLayer code on the OSM wiki[1]

Next I will tidy it up a little and wrap it in a script that produces POI
files for a bunch of different amenities (restaurants, supermarkets,
schools, public buildings) and make a demo map for others in my town to
use.

Is it worth putting this on the wiki as a worked example?

Thanks to Renaud for his helpful and useful replies.

Best wishes,

Andrew
[1] http://wiki.openstreetmap.org/wiki/Openlayers_POI_layer_example

XSLT follows.  Save it in a file called "amenities.xsl".  Here's how to
use it.

1.  Download an area of the map from OSM.  To do this, view the area of
the map you are interested in and click the 'Export' tab.  Under 'Format
to Export' choose 'OpenStreetMap XML Data' and click 'Export'.  Save the
file somewhere.  It will be called "map.osm"
2. Use the XSLT with the map.osm data file to extract the amenity you are
interested in.  For example, for libraries (I am using xsltproc in Linux):
xsltproc -o textfile.txt --stringparam amenity library amenities.xsl map.osm

It takes a little time.  Now you can use the file "textfile.txt" with the
OpenLayer example code.  I have chosen to use the red and blue icons to
show which points are derived from nodes, and which are derived from
areas, but there is no need to make such a distinction.

"amenities.xsl"
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE xsl:stylesheet [
<!ENTITY tab "	">
<!ENTITY cr "
">
<!ENTITY quot """>
]>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:param name="amenity">None</xsl:param>

<xsl:template
match="osm">lat&tab;lon&tab;title&tab;description&tab;icon&tab;iconSize&tab;iconOffset
<xsl:apply-templates select="node"/>
<xsl:apply-templates select="way"/>
</xsl:template>

<xsl:template match="node">
<xsl:for-each select="tag">
<xsl:if test='@k="amenity" and @v=$amenity'>
<xsl:value-of select='../@lat'/><xsl:text>&tab;</xsl:text>
<xsl:value-of select='../@lon'/><xsl:text>&tab;</xsl:text>
<xsl:value-of
select='../tag[@k="name"]/@v'/><xsl:text>&tab;</xsl:text>Amenity
node&tab;Ol_icon_red_example.png&tab;16,16&tab;-8,-8
</xsl:if>
</xsl:for-each>
</xsl:template>

<xsl:template match="way">
<xsl:variable name="nodes" select="../node[@id=current()/nd/@ref]"/>
<xsl:for-each select="tag">
<xsl:if test='@k="amenity" and @v=$amenity'>
<xsl:value-of select="sum($nodes/@lat) div
count($nodes)"/><xsl:text>&tab;</xsl:text>
<xsl:value-of select="sum($nodes/@lon) div
count($nodes)"/><xsl:text>&tab;</xsl:text>
<xsl:value-of
select='../tag[@k="name"]/@v'/><xsl:text>&tab;</xsl:text>Amenity
area&tab;Ol_icon_blue_example.png&tab;24,24&tab;0,-24
</xsl:if>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>





More information about the newbies mailing list