This example will demonstrate a few core pieces of functionality strung together to create an interesting and useful application. It will walk through the following steps:

  1. Creating a named query
  2. Using that named query as the input source of an XML Processing (XProc) pipeline
  3. Assigning a Perisistent URL (PURL) to the results of that XProc pipeline [Optional]
  4. Generating an OpenStreetMap display from a call to that PURL

Specifically, this example will generate a map of all the Nuclear Maps in the United States, plot those points on a map, and allow the user to click on any of those facilities and learn more about a facility.

1. Create a named query

This query must return data in a way that is compliant with use by OpenStreetMap. Here is what the query looks like in Callimachus:

As you can see above, the query specificly selects the URL (?link), name (?title), description (?description, which is always the same), and latitute (?lat) and longitude (?long) of the facility. This query generates a SPARQL Protocol and RDF Query Language (SPARQL) XML result set which must now be transformed into Geographically Encoded Objects for Rich Site Summary (GeoRSS) via an XProc pipeline.

2. Use that named query as the input source of an XProc pipeline

To generate GeoRSS from SPARQL XML results, use an XProc pipeline with the appropriate EXtensible Stylesheet Language (XSL) stylesheet.

<?xml version="1.0" encoding="UTF-8" ?> 
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library"> 

<p:serialization port="result" media-type="application/rss+xml" method="xml" /> 

<p:load href="nukemap.rq?results" /> 

<p:xslt name="nukemap"> 
  <p:input port="stylesheet"> 
    <p:document href="sparql-georss.xsl" /> 
  </p:input> 
</p:xslt>

</p:pipeline>

There a small number of tags here each with their own distinct purpose. The serialization tag (<p:serialization>) uses the port attribute (port="result") to declare that the results of the pipeline will be a form of RSS+XML (media-type="application/rss+xml"). The load tag (<p:load>) executes the named query created in step 1 and returns the results to the pipeline.

XSL Transformation is a language for transforming one form of an XML document into another form of XML. In this case we'll be going from SPARQL XML to GeoRSS.  The XSLT tag (<p:xslt>) declares the start of the XSLT and names it "nukemap". Inside that transformation, the input tag (<p:input>) uses the port attribute (port="stylesheet") to specify the stylesheet that will be applied to the results of the named query. The document tag (<p:document>) specifies the URL of the stylesheet to be used (href="sparql-georss.xsl") which in this case is located in the same directory as the pipeline.

3. Assign a PURL to the results of that XProc pipeline [Optional]

To enable the ability to set caching control, as well as move or edit the XProc pipeline without having to change the link, it would be wise to assign a PURL to the results of the pipeline. However, if you are simplying putting together a prototype, or do not anticipate relocating your resource, a PURL is entirely optional. The map can call the URL of the XProc pipeline without the intermediary PURL. However, if you were to create a PURL it would look like this:

The PURL is given a name (nukemap) and a type of 200 which means that the results of this PURL will be copied from their location. Content location specifies where the PURL should look for content, which in this case we want to be the results of our XProc pipeline (nukemap.xpl?results). Lastly, we can set cache control on the PURL. This is a way of improving efficiency by not having to constantly fetch new results if a number of requests are made in quick succession. In this case we are specifying that if multiple requests are made over the course of 3,600 seconds, rather than following the PURL and getting new results each time, simply grab results from cache. 

4. Generate OpenStreetMap display from a PURL

The last step of this example is to tie it all together. At this point there is now a single PURL (nukemap) that can be accessed which will return the results of the named query in GeoRSS format. Now that PURL needs to be worked into the OpenStreetMap code as the input for generating the map itself. If you are unfamiliar with OpenStreetMaps (OSM) at a high level, it would be beneficial to read some of their basic documentation and examples before diving into this code.

<?xml-stylesheet type="text/xsl" href="/callimachus/template.xsl"?> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
  <title>U.S. Nuclear Plants</title> 
  <script src="//www.openlayers.org/api/OpenLayers.js"></script> 
  <script> 
  // <![CDATA[ 
    jQuery(function() { 
      var map = new OpenLayers.Map("mapdiv"); 
      map.addLayer(new OpenLayers.Layer.OSM()); 
      
      map.addLayer(new OpenLayers.Layer.GeoRSS("My Points", "nukemap", { 
        tileOptions: { crossOriginKeyword: null } 
      })); 

      map.setCenter(new OpenLayers.LonLat("-98.0", "38.0").transform( 
          new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984 
          map.getProjectionObject() // to Spherical Mercator Projection 
        ), 4 // Zoom level 
      ); 
    }); 
  // ]]> 
  </script> 

  <style> 
    .leaflet-map-pane img, /* OpenStreetMap */ 
    .olMapViewport img { /* general OpenLayers maps */ 
      max-width: none; 
     } 
  </style> 

</head> 
<body> 
  <h1>U.S. Nuclear Plants</h1> 
  <table width="100%"> 
    <tbody> 
      <tr> 
        <td style="width:100%">
          <div id="mapdiv" style="height:800px"></div>
        </td> 
      </tr> 
    </tbody> 
  </table> 
</body> 
</html>

There is really one important line that makes this code different from a standard implementation of OSM and that line is:

map.addLayer(new OpenLayers.Layer.GeoRSS("My Points", "nukemap", { tileOptions: { crossOriginKeyword: null } }));

which is where we call the nukemap PURL as the source of our GeoRSS. With the infrastructure in place it is a simple adjustment to standard code that allows for a simple collection of data files to become an interesting visualization of nuclear plants in the United States.

NB: Twitter Bootstrap (which Callimachus' default theme is based on) has a default setting that intereferes with OpenStreetMap. Luckily this can be easily overcome with a bit of CSS at the top of the page. The code is below.

<style> 
  .leaflet-map-pane img, /* OpenStreetMap */ 
  .olMapViewport img { /* general OpenLayers maps */ 
    max-width: none; 
  } 
</style>