Map Bureau Home



RDFMapper: an RDF-Based Web Mapping Service
Version 2.0

This document describes version 2.0 of RDFMapper. Version 1 will continue to be supported.

RDFMapper is a web service that searches an RDF or RSS file for resources with geographic locations, and returns a map overlayed with dots representing located resources. Clicking on a dot displays a web page representing the clicked resource (see these examples). Arbitrary images can be treated as maps, so the service can be used for any kind of image annotation.

RSS is translated into RDF before processing (except for RSS 1.0, which is already RDF). For brevity, RSS is mentioned in what follows only when the non-RDF variants of RSS (RSS 0.9x and RSS 2.0) require explicit discussion.

The parameters to the web service specify what RDF file is to be mapped, the form of the page into which the map will be embbeded, what basemap (eg of San Francisco or the world) is to appear in the background, how to extract the relevant data from an RDF resource for mapping, and how to generate HTML associated with mapped items. The extraction and generation parameters are formulated as programs in Fabl, an RDF-based programming language. A utility library at http://www.mapbureau.com/libsrc/rdfmapper_utils-2.0.fbl. contains extractors and generators that will suffice for many applications, obviating the need for Fabl programming in these cases.

Exploiting the full flexibility of RDFMapper does, however, require Fabl programming. Fabl provides a simple framework for RDF-related software development. Its syntax and object manipulation constructs should be familiar to most programmers, and the sample Fabl programs appearing in this document are intended to be comprehensible without prior familiarity with the language. For details, see the Fabl manual. The Fabl language runs on the RDFMapper server, so need not be installed by developers of RDFMapper content. However, Fabl is an open source language, and can be downloaded at no cost from the Fabl site.

No restriction is placed on the way in which geographic location is encoded in the RDF content; a parameter to the service is the algorithm for extracting locations, and this algorithm may be anything the user chooses. However, the W3C RDFIG Geo vocabulary is recommended.

The base URL of the service is http://www.mapbureau.com/rdfmapper/2.0/m.fsp; the parameters may be appended after a "?" in the usual form of an HTTP GET request. RDFMapper also accepts parameters from HTTP POSTs.

RDFMapper bears some general resemblance to the web mapping and web feature services as specified by the OpenGIS consortium, but differs in using RDF as the fundamental technology, and in that it parameterizes the process of generating locations and HTML representing mapped items. A limitation is that RDFMapper only displays locations, not, for example, curves. There is a substantial amount of work going on concerning RDF and geography; see the GeoInfo wiki for links.

Here is an example of an RDFMapper invocation, implemented as an HTML form (which, when submitted, sends its entries as HTTP Post arguments):


basemap
content
syntax
extractor
pageGen
itemTitleGen
itemGen
pageTitle
styleSheet

The form is operational; click on "Submit", and you will see an RDFMapper-generated map.

Here's the HTML for a form with equivalent functionality, but which is invisible, and is launched by a link rather than a submit button.


<form  id ="form1"  ACTION="http://www.mapbureau.com/rdfmapper/2.0/m.fsp" 
      enctype="text/plain"
      METHOD="POST">
<input type="hidden" name="basemap" 
        value="http://www.mapbureau.com/basemaps/croppedworld.0.xml">
<input type="hidden" name="content" 
        value="http://www.mapbureau.com/userdata/donalda/worstplacesforjournalists/data.xml">
<input type="hidden" name="syntax" value="rdf">
<input type="hidden" name="extractor" value="extractLocation">
<input type="hidden" name="pageGen" value="pageGen0">
<input type="hidden" name="itemTitleGen" value="itemTitleGen0">
<input type="hidden" name="itemGen" value="itemGen0">
<input type="hidden" name="pageTitle" 
    value="Worst Places for Journalists (from <a href='http://www.cpj.org'>CPJ</a>)">
<input type="hidden" name="styleSheet" value="http://www.mapbureau.com/rdfmapper/2.0/style1.css">
</form>
<a href = "javascript:document.forms['form1'].submit();">Submit</a>

Here are the details:

Parameters to the service

basemap

The basemap parameter is the URL of a file in the RDFMap format describing the basemap. An RDFMap file links to a jpeg or swf (Macromedia Flash) image, and optionally specifies the geographic projection associated with the image; this projection information is required for geographic mapping (as opposed to image annotation). http://www.mapbureau.com/basemaps/astoria.0.xml is an example an RDFMap file using the UTM Zone 10 North projection. This catalog contains basemaps that can be used with RDFMapper. When viewing the catalog, the line beneath the map displays the URL of the RDFMap file for the current selection; this URL is suitable for use as the basemap parameter to RDFMapper.

content

URL of the RDF file containing the data to be mapped.

syntax

Specifies the syntax of the content file. Options are rdf (for the RDF/XML syntax) and rss for the non-RDF variants RSS 0.9x and RSS 2.0. The non-RDF variants are transformed into RDF before processing. RDF and RSS parsing is performed by the Raptor parser toolkit.

Many of the remaining parameters to the service are algorithmic, and represented by Fabl programs. A utility library for RDFMapper is available at http://www.mapbureau.com/libsrc/rdfmapper_utils-2.0.fbl. If the functions appearing in the library suit the purposes of an application, there is no need to develop new versions.

extractor

extractor denotes a Fabl function that, when given an RDF resource, returns a geom2d:Point representing its location, or nil. (The geom2d vocabulary is documented at http://www.mapbureau.com/rdfgeom2d1.0). RDFMapper maps all resources in the content file for which extractor returns a non-nul value. The extractor parameter may take the form,

<function_name>

or

<URL-of-Fabl-code-file>#<function_name>

In the former case, the function is taken from the above-mentioned RDFMapper utility library, and otherwise, from the given Fabl code file. More precisely, since Fabl is a polymorphic language, the function in question is the polymorphic variant of <function_name> with one input of type Resource.

Example:

 extractor=http://www.mapbureau.com/rdfmapper/2.0/examples/ex1.fbl#extractGeoLatLong
 

This sets the extractor to the function:

 geom2d:Point function extractGeoLatLong(Resource x)
 {
   var geom2d:Point rs;
   if  ((count(x,geo:lat)>0) && (count(x,geo:long)>0))
	   {
	   rs = new(geom2d:Point);
	   rs . geom2d:x = x.geo:long;
	   rs . geom2d:y = x.geo:lat;
	   return rs;
	   }
   return nil ~  geom2d:Point; 
}

defined in http://www.mapbureau.com/rdfmapper/2.0/examples/ex1.fbl. The function count(<resource>,<property>) determines how many values the given <property> takes on for the given <Resource>. The syntax

<resource>.<property>

selects one value of the given <property> on the given <Resource>. So, in English, the above code reads: "if geo:lat and geo:long each take on at least one value on x, then extract the corresponding values, package them a geom2d:Point, and return that Point.

The initial lines of the file http://www.mapbureau.com/rdfmapper/2.0/examples/ex1.fbl are

install(namespace('geom2d'));
install(namespace('geo'));
setHomeAndTopic(resource("http://www.mapbureau.com/rdfmapper/2.0/examples/ex1"));

The first two lines install definitions from the needed namespaces. setHomeAndTopic sets the "home" namespace to http://www.mapbureau.com/rdfmapper/2.0/examples/ex1, and also sets the foaf:topic of the file being loaded to this same value. The practical effect is that functions defined thereafter can be referenced relative to the containing file with "#". Details on these matters can be found in the Fabl manual.

Fabl source code files have the extension .fbl, while Fabl files that have been compiled into byte-code form have extension .fb (for "Fabl Binary"). Either is acceptable as a code source in a parameter to RDFMapper. If the code for performing RDFMapper work is lengthy, compilation is encouraged, since loading Fabl source can be time consuming, whereas loading of Fabl in its byte-code form is very fast (the execution time of the code once loaded is not affected). The RDFMapper utility library is loaded in compiled form from http://www.mapbureau.com/lib/rdfmapper_utils-2.0.fb. Compilation requires download of the Fabl language implementation from fabl.net.

See the section at the bottom of this document for suggestions on debugging Fabl extractors and generators

itemGen

itemGen denotes a function that generates HTML from an RDF resource. When a dot on the map representing a resource is clicked, this is the HTML that is displayed. The function should take two arguments: (1) a string onto which the generated HTML should be appended, and (2) the resource for which HTML is to be generated.

Here is a simple example:


void function itemGenExample(string rs,Resource x)
{
   var string dc,lnk,ttl;
   dc = x . dc:description ~ string;
   ttl = x . dc:title ~ string;
   if (nnul(ttl)) 
      rs * "<p><b>Title:</b></p><p>{ttl}</p>";
   if (nnul(dc)) 
      rs * "<p><b>Description:</b>{dc}</p>";
}

The "~" is Fabl's type cast operator; x~type corresponds in meaning to (type)x in C. The "*" operator appends its second argument to its first by side effect. Fabl expressions surrounded by curly brackets ({}) within double quotes ("") are evaluated, so that, "two plus three is {2+3}" is equivalent to "two plus three is 5". See the Fabl manual section on strings for details.

itemTitleGen

In addition to displaying dots on a map, RDFMapper displays a directory listing each of the mapped resources by title - itemTitleGen determines the title to use for this purpose. Unlike itemGen, it takes one argument, and returns the title, as in :

string function itemTitleGenExample(Resource x)
{
   return x . dc:title ~ string;
}

pageTitleGen

pageTitleGen (optional) extracts a title for the map as a whole. It is applied to each resource in the content file, and if it returns a non-nul value for any of them, then the first such non-nul value is used. Typically, pageTitleGen extracts a non-nul title only for a resource whose type indicates that it is top-level (eg rss:channel for RSS). Example:

string function channelTitle(Resource itm)
{
  if (!hasType(itm,rss:channel)) return nil~string;
  return itm . dc:title~string;
}

pageTitle

The title of the page may be specified explicitly with the optional pageTitle parameter. The string to be used as the title, rather than a function to compute the title, should be supplied as the value of this parameter.

pageGen

Instead of dictating a particular layout for the map page, RDFMapper passes the needed materials to the pageGen function, which in turn performs the layout in a manner appropriate to the application. pageGen takes three arguments: (1) the title of the page as determined by other RDFMapper parameters, (2) content computed by RDFMapper for placement in the <head> section of the page, and (3) HTML for the map itself as computed by RDFMapper for placement at the top of the <body> section of the page. Example:

string function pageGen0(string title,inHead,map)
{
return
"<html>
<head>{inHead}<title>RDFMapper</title></head>
<body onLoad=\"listItems();\">
{map}
<div id = \"pageTitle\">{title}</div>
<div id = \"listItems\">
  <center><a href=\"javascript:listItems();\">List all items</a></center></div>
<div id = \"item\"></div>
</body>
</html>";
}

The map argument, computed by RDFMapper, consists of HTML and Javascript that have the effect of embedding the requested map, and of "wiring it" to other content in the page with the correct logic. The pageGen function may, at the developer's option, add whatever additional content is wanted into the page. However, a div with id "item" should be included - this is where the directory of items, and also the HTML representing each item, will be directed by the logic in map.

It is also advisable to follow the example above in its invocation of the Javscript function listItems. listItems places the directory of all mapped items into the item div; the above version of pageGen performs this action at load time, and also provides the link with text "list all Items" for effecting this on demand.

These loose constraints on page generation mean that RDFMapper maps can be embedded freely in any kind of web page.

styleSheet

This parameter specifies the URL of the style sheet for the map page. Positioning and other style parameters should be specified at least for the div with id item, and for the class mapclass (this is the class of the div in which the map appears.) If not specified, the default style sheet is http://www.mapbureau.com/rdfmapper/2.0/style.css. The parts of this file that specify styles for the item div, and for mapclass are:

div#item {  
   position: absolute; left: 48%; top: 8%; width:48%;  height: 90%; 
   border-style: solid;
   border-width: 1px;
   border-style: solid;
   background-color: #ffffee;
   overflow:auto;
   padding:1em;
   }

and

.mapclass{ 
   background-color: #ffffee; 
   position: absolute; width: 45%; top: 8%; left: 2%; height: 90%;
   border-style: solid;
   border-width: 1px;
   border-color: #ff9933; 
   }

The style sheet should also specify styles for other elements in the page as generated by pageGen.

Debugging Extractors and Generators

The Fabl code appearing below loads a sample RDF file, culls the loaded resources using extractLocation, and applies myItemGen to the first resource that survives the cull. You can employ code of this kind to check that your own extractors and generators are operating correctly. (Failures of extractors and generators are sometimes hard to diagnose based on RDFMapper behavior alone).

For those who have not installed Fabl on their own systems, a web service is available at http://fabl.net/eval/file.html for uploading and evaluating the contents of Fabl source files.




install(namespace('geom2d'));
install(namespace('dc'));
install(namespace('rss'));
install(namespace('geo'));
install(namespace('content'));

// this makes the code from the utility libary available by adding
// the library to the path.
push(path,load("http://www.mapbureau.com/lib/rdfmapper_utils-2.0.fb"));


// subjects will contain all resources in the loaded file that are subjects of RDF triples
var subjects = new(SeqOf(ob));
load(subjects,"http://www.mapbureau.com/userdata/donalda/worstplacesforjournalists/data.xml");


var locatedItems = cull(subjects,extractLocation[ob]~Function(ob,ob));
var lnl = length(locatedItems);
writeln("Length of locatedItems = ",lnl);

{if (lnl == 0) {writeln("No Located Items");quit()}}



void function myItemGenerator(string s,Resource itm)
{
   var string ttl;
   ttl = itm . dc:description ~ string;
   if (nul(ttl))  s * "<p>Untitled</p>";
   else s * "<p><b>Title:</b>{ttl}</p>";
}

//test myItemGenerator on the first item that survived the cull

var bf = "";

myItemGenerator(bf,locatedItems[0]);
bf;