Overview of Linked Data Demo

Overview of the linked data Buildings Visualisation demo using data from UoE open Repository.

The demo is here http://mab.edina.ac.uk/oarj-linkeddata/ed-rdf.html

The Map
The basis of the map is OpenStreetMap from http://www.openstreetmap.org/ a  is a freely editable map of the whole world.

It is displayed using openlayers javascript library. http://openlayers.org/

OpenLayers is an opensource library that can display map tiles and markers loaded from any source.
test

 

Use case outline.

The user workflow.  The user does a search and navigates down to a buiding shape view.

The search tool is created by extending the openlayers zoombox control and overriding the zoomBox function.

OpenLayers.Util.extend(zoomBox, {
zoomBox: function (position) {
this.notice(position);

},

notice : function(bounds) {
var leftBottom = new OpenLayers.Pixel(bounds.left, bounds.bottom);
var rightTop = new OpenLayers.Pixel(bounds.right, bounds.top);
var southWest = map.getLonLatFromPixel(leftBottom);
var northEast = map.getLonLatFromPixel(rightTop);

southWest = southWest.transform(map.projection,
map.displayProjection);
northEast = northEast.transform(map.projection,
map.displayProjection);
var south = southWest.lat;
var west = southWest.lon;
var east = northEast.lon;
var north = northEast.lat;
if(!isNaN(south) || !isNaN(north) || !isNaN(east) || !isNaN(west)){
addEdDataMarkersToLayer(east, west, north, south);
//reset to the default control
panel.activateControl(defaults);
}

 

 

 

}
});

When the user finishes area selection, a mouseup event is captured and a bounding box of the area is sent to the server.

On the server side the bounding box is used in the creation of a rdf sparql query to the EoU sparql end point.The sparl end point is at http://data.inf.ed.ac.uk/query
The underlying datascource is 4Store

The sparql query takes the form of

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX ospc: <http://data.ordnancesurvey.co.uk/ontology/postcode/>
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#>
PREFIX rooms: <http://vocab.deri.ie/rooms#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?building ?label ?street ?lat ?long ?postcode ?locality ?osmid WHERE {
?address geo:lat ?lat  .

?address geo:long ?long .
FILTER ( xsd:double(?long)  > ").append(bb.getWest())
&&  xsd:double(?long)  < ").append(bb.getEast())
&&  xsd:double(?lat)  > ").append(bb.getSouth())
&&  xsd:double(?lat)  < ").append(bb.getNorth())
?address vcard:street-address ?street .
?address vcard:locality ?locality .
?address foaf:based_near  ?osmid .
?address ospc:postcode ?postcode .
?building vcard:adr ?address .
?building rdfs:label ?label .
}

The FILTER clause does the basic bounding box query. Although the query would execute faster if we had the geometries using a spatial index and use extended syntax.
With Portablity and with a small dataset in mind, I used basic sparql to make sure it worked on both a Virtuoso RDF store as well as 4Store.

It is a java web app and we are using Jena library which creates an abstraction for querying remote sparql end points.

Query sparql = QueryFactory.create(geoQuery.toString());

QueryExecution x = QueryExecutionFactory.sparqlService(
sparqlEndPoint,geoQuery.toString());
ResultSet results = x.execSelect();

List<JSONObject> jsonList = new ArrayList<JSONObject>();

int counter = 0;
while (results.hasNext()) {
counter++;
JSONObject json = new JSONObject();
QuerySolution rs = results.nextSolution();

The results of the search are passed back to the browser using json.

[{
"label" : "William Robertson Building",
"geo:lat" : 55.94384087597896,
"geo:long" : -3.1871938705444336,
"postcode" : "http://data.ordnancesurvey.co.uk/id/postcodeunit/EH89JY",
"locality" : "central",
"street" : "George Square, Edinburgh, EH8 9JY",
"osmid" : "5325199"
}, {
"label" : "Hugh Robson Building",
"geo:lat" : 55.94427947240619,
"geo:long" : -3.1899189949035645,
"postcode" : "http://data.ordnancesurvey.co.uk/id/postcodeunit/EH89XD",
"locality" : "central",
"street" : "George Square, Edinburgh, EH8 9XD",
"osmid" : "27595323"
}...

The json is parsed and the geo:lat and geo:long rdf properties are used to place markers on the map.
The rest of the properties are used to build a pop up for the marker.

var marker = feature.createMarker();

var markerClick = function(evt) {

for ( var i = map.popups.length - 1; i >= 0; --i) {
map.popups[i].hide();
}
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;

var content = getContentFromTags(tags, featureShape);
//show feature area

 

 

 

currentPopup.setContentHTML(content);
OpenLayers.Event.stop(evt);
};

If the rdf resolves to an open street map feature shape for the building a link is created on the popup allowing the user to display this shape file.
OpenStreetMap shapes are used as an interim solution until we have full access to the highly detailed estates and builds floor plans which we could overlay instead.

Displaying the shape files on the map.

There are a varity of formats we can consume to display the building shapes on the map, we are currently using KML.

formats = {
'in' : {
wkt : new OpenLayers.Format.WKT(in_options),
geojson : new OpenLayers.Format.GeoJSON(in_options),
georss : new OpenLayers.Format.GeoRSS(in_options),
gml2 : new OpenLayers.Format.GML.v2(gmlOptionsIn),
gml3 : new OpenLayers.Format.GML.v3(gmlOptionsIn),
kml : new OpenLayers.Format.KML(kmlOptionsIn),
atom : new OpenLayers.Format.Atom(in_options)
},


Maybe in the future we could use the WKT format. The idea being to generate the buildings rdf with a dc:spatial (wkt polygons) to describe the building shapes and display them directly without the extra step to openstreetmaps.

We use function ajax call to retrieve the kml shape file and and it to a vector layer.

getFeatureShapeInKml(shapeId) {

var strUrl = "PlaceMarkServlet?osmid=" + shapeId;
var strReturn = "";

jQuery.ajax({
url : strUrl,
success : function(kml) {
strReturn = kml;
},
async : false
});

 

 

return strReturn;
}

On the server the openstreetmap derived kml is queried with the OSM id and the placemark is returned using a simple xpath query.

XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
String xpathExp = String
.format("/kml/Document/Folder/Placemark[ExtendedData/SchemaData/SimpleData[@name='osm_id']=%s]",
osmId);

XPathExpression expr = xpath.compile(xpathExp);

Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
StringWriter sw = new StringWriter();
for (int i = 0; i < nodes.getLength(); i++) {

transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StreamResult out = new StreamResult(sw);
DOMSource source = new DOMSource(nodes.item(i));

transformer.transform(source, out);

 

 

 

 

//add placemarker to return
output = String.format(output, sw.toString());
}

This could be with replaced with geometries derived from the university estates and building instead.

Pages I found useful do this investigation.

 

Sparql tutorial – http://www.cambridgesemantics.com/2008/09/sparql-by-example/

Installing virtuoso on ubuntu – http://ods.openlinksw.com/wiki/main/Main/VOSUbuntuNotes

RDF and Jena – http://jena.sourceforge.net/tutorial/RDF_API/





 

This entry was posted in Uncategorized by mking4. Bookmark the permalink.

Comments are closed.