/* * Copyright (c) 2010, University of Bristol * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2) Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3) Neither the name of the University of Bristol nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ package org.ilrt.mca.harvester.geo; import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner; import com.hp.hpl.jena.reasoner.rulesys.Rule; import com.hp.hpl.jena.sparql.vocabulary.FOAF; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; import org.ilrt.mca.harvester.ResponseHandler; import org.ilrt.mca.vocab.WGS84; import org.ilrt.mca.vocab.MCA_GEO; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; /** * @author Mike Jones (mike.a.jones@bristol.ac.uk) */ public class OpenStreetMapResponseHandlerImpl implements ResponseHandler { public OpenStreetMapResponseHandlerImpl() { model = ModelFactory.createDefaultModel(); // get the rules InputStream is = getClass().getResourceAsStream("/rules/osmdata.rules"); rules = Rule.parseRules(Rule.rulesParserFromReader( new BufferedReader(new InputStreamReader(is)))); } @Override public Model getModel(String sourceUri, InputStream is) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(is); NodeList nodeList = doc.getFirstChild().getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeName().equals("node")) { // the attributes on the node hold the id and lat/long; use these // to create uri (id) and initial data (lot/long) Resource resource = createResource(node.getAttributes()); NodeList tagList = node.getChildNodes(); for (int j = 0; j < tagList.getLength(); j++) { Node tag = tagList.item(j); if (tag.getNodeName().equals("tag")) { parseTagElement(resource, tag); } } model.add(resource.getModel()); } } fireRules(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return model; } @Override public boolean isSupportedMediaType(String mediaType) { return mediaType.startsWith("text/xml") || mediaType.startsWith("application/xml"); } /** * The node id and the latitude and longitude are stored as attributes on the node * element. We get these via a NamedNodeMap and create a URI and appropriate * WGS84 properties. * * @param map NamedNodeMap that holds attributes of interest * @return a Resource object that holds a URI and lat/long values */ private Resource createResource(NamedNodeMap map) { // create the URI Resource resource = model.createResource("http://www.openstreetmap.org/api/0.6/node/" + map.getNamedItem("id").getTextContent()); // add the latitude and longitude resource.addProperty(WGS84.latitude, map.getNamedItem("lat").getTextContent(), XSDDatatype.XSDdouble); resource.addProperty(WGS84.longitude, map.getNamedItem("lon").getTextContent(), XSDDatatype.XSDdouble); // add type resource.addProperty(RDF.type, WGS84.Point); return resource; } /** * The OSM data is encapsulated in lots of Tag elements with key (k) and value (v) * attribute values. We pull this lexical information and covert it to RDF types * and literals. * * @param resource the Resource object we will add additional information. * @param tag the XML node that holds the OSM data. */ private void parseTagElement(Resource resource, Node tag) { // get the attributes in the tag element NamedNodeMap map = tag.getAttributes(); // a name becomes a label if (map.getNamedItem("k").getTextContent().equals("name")) { resource.addProperty(RDFS.label, map.getNamedItem("v").getTextContent(), XSDDatatype.XSDstring); } // we are interested in amenities if (map.getNamedItem("k").getTextContent().equals("amenity")) { resource.addProperty(RDF.type, MCA_GEO.Amenity); // values can be separated by semicolons parseValue(map.getNamedItem("v").getTextContent(), resource); } // we are interested in amenities if (map.getNamedItem("k").getTextContent().equals("shop")) { resource.addProperty(RDF.type, MCA_GEO.Shop); // values can be separated by semicolons parseValue(map.getNamedItem("v").getTextContent(), resource); } // does the node have a website? if (map.getNamedItem("k").getTextContent().equals("website")) { resource.addProperty(FOAF.homepage, model.createResource(map.getNamedItem("v") .getTextContent())); } // does the node have an email address? if (map.getNamedItem("k").getTextContent().equals("email")) { resource.addProperty(FOAF.mbox, model.createResource("mailto:" + map.getNamedItem("v") .getTextContent())); } // does the node have a telephone number? if (map.getNamedItem("k").getTextContent().equals("phone")) { resource.addProperty(FOAF.phone, model.createResource("tel:" + map.getNamedItem("v") .getTextContent())); } // does the node have an atm if (map.getNamedItem("k").getTextContent().equals("atm")) { if (map.getNamedItem("v").getTextContent().equals("yes")) { resource.addProperty(RDF.type, MCA_GEO.BuildingWithCashPoint); } } } private void parseValue(String value, Resource resource) { // values can be separated by semicolons String[] values = value.split(";"); // for each value create a tag and type, if appropriate for (String value1 : values) { resource.addProperty(MCA_GEO.hasTag, value1); } } void fireRules() { model.add(ModelFactory.createInfModel(new GenericRuleReasoner(rules), model)); } private Model model; private final List<Rule> rules; }