add support for OpenLS (Location Utility Service), thanks cmoullet for the great example, p=me,r=cmoullet,erilem,fredj (closes #2953)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@11781 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
bartvde
2011-03-30 13:27:30 +00:00
parent 76f1987a8b
commit 464aed9d75
8 changed files with 667 additions and 1 deletions

86
examples/openls.html Normal file
View File

@@ -0,0 +1,86 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css"/>
<link rel="stylesheet" href="style.css" type="text/css"/>
<title>OpenLS: Geocoding Example</title>
<script type="text/javascript" src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map, layer;
function init() {
OpenLayers.ProxyHost = "proxy.cgi?url=";
map = new OpenLayers.Map('map', {
controls: [
new OpenLayers.Control.PanZoom(),
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.Navigation()
]
});
layer = new OpenLayers.Layer.OSM("OpenStreetMap", null, {
transitionEffect: 'resize'
});
map.addLayers([layer]);
map.zoomToMaxExtent();
}
function submitform() {
var queryString = document.forms[0].query.value;
OpenLayers.Request.POST({
url: "http://www.openrouteservice.org/php/OpenLSLUS_Geocode.php",
scope: this,
failure: this.requestFailure,
success: this.requestSuccess,
headers: {"Content-Type": "application/x-www-form-urlencoded"},
data: "FreeFormAdress=" + encodeURIComponent(queryString) + "&MaxResponse=1"
});
}
function requestSuccess(response) {
var format = new OpenLayers.Format.XLS();
var output = format.read(response.responseXML);
if (output.responseLists[0]) {
var geometry = output.responseLists[0].features[0].geometry;
var foundPosition = new OpenLayers.LonLat(geometry.x, geometry.y).transform(
new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject()
);
map.setCenter(foundPosition, 16);
} else {
alert("Sorry, no address found");
}
}
function requestFailure(response) {
alert("An error occurred while communicating with the OpenLS service. Please try again.");
}
</script>
</head>
<body onload="init()">
<h1 id="title">OpenLS Geocoding Example</h1>
<div id="tags">
OpenLS, XLS, Geocoding
</div>
<p id="shortdesc">
Show how to use an OpenLS service.
</p>
<form name="input" action="javascript: submitform();" method="post">
<label for="query">Search for address:</label> <input type="text" id="query" size=50 name="query"
value="Rue des Berges 37 Payerne"/>
<input type="submit" value="Submit"/>
</form>
<br>
<div id="map" class="smallmap"></div>
<div id="docs">
<p>
Geocoding example using the http://www.openrouteservice.org/ OpenLS service. Recenter to the first item of the results.
</p>
</div>
</body>
</html>

View File

@@ -21,7 +21,7 @@ allowedHosts = ['www.openlayers.org', 'openlayers.org',
'sigma.openplans.org', 'demo.opengeo.org',
'www.openstreetmap.org', 'sample.azavea.com',
'v2.suite.opengeo.org', 'v-swe.uni-muenster.de:8080',
'vmap0.tiles.osgeo.org']
'vmap0.tiles.osgeo.org', 'www.openrouteservice.org']
method = os.environ["REQUEST_METHOD"]

View File

@@ -329,6 +329,9 @@
"OpenLayers/Format/OWSContext/v0_3_1.js",
"OpenLayers/Format/WMTSCapabilities.js",
"OpenLayers/Format/WMTSCapabilities/v1_0_0.js",
"OpenLayers/Format/XLS.js",
"OpenLayers/Format/XLS/v1.js",
"OpenLayers/Format/XLS/v1_1_0.js",
"OpenLayers/Layer/WFS.js",
"OpenLayers/Control/GetFeature.js",
"OpenLayers/Control/MouseToolbar.js",

View File

@@ -0,0 +1,118 @@
/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format/XML.js
*/
/**
* Class: OpenLayers.Format.XLS
* Read/Wite XLS (OpenLS). Create a new instance with the <OpenLayers.Format.XLS>
* constructor. Currently only implemented for Location Utility Services, more
* specifically only for Geocoding. No support for Reverse Geocoding as yet.
*
* Inherits from:
* - <OpenLayers.Format.XML>
*/
OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML, {
/**
* APIProperty: defaultVersion
* {String} Version number to assume if none found. Default is "1.1.0".
*/
defaultVersion: "1.1.0",
/**
* APIProperty: version
* {String} Specify a version string if one is known.
*/
version: null,
/**
* Property: parser
* {Object} Instance of the versioned parser. Cached for multiple read and
* write calls of the same version.
*/
parser: null,
/**
* Constructor: OpenLayers.Format.XLS
* Create a new parser for XLS.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*/
initialize: function(options) {
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: write
* Write out an XLS request.
*
* Parameters:
* request - {Object} An object representing the LUS request.
* options - {Object} Optional configuration object.
*
* Returns:
* {String} An XLS document string.
*/
write: function(request, options) {
var version = (options && options.version) ||
this.version || this.defaultVersion;
if(!this.parser || this.parser.VERSION != version) {
var format = OpenLayers.Format.XLS[
"v" + version.replace(/\./g, "_")
];
if(!format) {
throw "Can't find an XLS parser for version " +
version;
}
this.parser = new format(this.options);
}
var root = this.parser.write(request);
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
},
/**
* APIMethod: read
* Read an XLS doc and return an object representing the result.
*
* Parameters:
* data - {String | DOMElement} Data to read.
* options - {Object} Options for the reader.
*
* Returns:
* {Object} An object representing the GeocodeResponse.
*/
read: function(data, options) {
if(typeof data == "string") {
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
}
var root = data.documentElement;
var version = this.version;
if(!version) {
version = root.getAttribute("version");
if(!version) {
version = this.defaultVersion;
}
}
if(!this.parser || this.parser.VERSION != version) {
var format = OpenLayers.Format.XLS[
"v" + version.replace(/\./g, "_")
];
if(!format) {
throw "Can't find an XLS parser for version " +
version;
}
this.parser = new format(this.options);
}
var xls = this.parser.read(data, options);
return xls;
},
CLASS_NAME: "OpenLayers.Format.XLS"
});

View File

@@ -0,0 +1,307 @@
/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format/XLS.js
* @requires OpenLayers/Format/GML/v3.js
*/
/**
* Class: OpenLayers.Format.XLS.v1
* Superclass for XLS version 1 parsers. Only supports GeocodeRequest for now.
*
* Inherits from:
* - <OpenLayers.Format.XML>
*/
OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
/**
* Property: namespaces
* {Object} Mapping of namespace aliases to namespace URIs.
*/
namespaces: {
xls: "http://www.opengis.net/xls",
gml: "http://www.opengis.net/gml",
xsi: "http://www.w3.org/2001/XMLSchema-instance"
},
/**
* Property: regExes
* Compiled regular expressions for manipulating strings.
*/
regExes: {
trimSpace: (/^\s*|\s*$/g),
removeSpace: (/\s*/g),
splitSpace: (/\s+/),
trimComma: (/\s*,\s*/g)
},
/**
* APIProperty: xy
* {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
* Changing is not recommended, a new Format should be instantiated.
*/
xy: true,
/**
* Property: defaultPrefix
*/
defaultPrefix: "xls",
/**
* Property: schemaLocation
* {String} Schema location for a particular minor version.
*/
schemaLocation: null,
/**
* Constructor: OpenLayers.Format.XLS.v1
* Instances of this class are not created directly. Use the
* <OpenLayers.Format.XLS> constructor instead.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*/
initialize: function(options) {
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
* Method: read
*
* Parameters:
* data - {DOMElement} An XLS document element.
* options - {Object} Options for the reader.
*
* Returns:
* {Object} An object representing the XLSResponse.
*/
read: function(data, options) {
options = OpenLayers.Util.applyDefaults(options, this.options);
var xls = {};
this.readChildNodes(data, xls);
return xls;
},
/**
* Property: readers
* Contains public functions, grouped by namespace prefix, that will
* be applied when a namespaced node is found matching the function
* name. The function will be applied in the scope of this parser
* with two arguments: the node being read and a context object passed
* from the parent.
*/
readers: {
"xls": {
"XLS": function(node, xls) {
xls.version = node.getAttribute("version");
this.readChildNodes(node, xls);
},
"Response": function(node, xls) {
this.readChildNodes(node, xls);
},
"GeocodeResponse": function(node, xls) {
xls.responseLists = [];
this.readChildNodes(node, xls);
},
"GeocodeResponseList": function(node, xls) {
var responseList = {
features: [],
numberOfGeocodedAddresses:
parseInt(node.getAttribute("numberOfGeocodedAddresses"))
};
xls.responseLists.push(responseList);
this.readChildNodes(node, responseList);
},
"GeocodedAddress": function(node, responseList) {
var feature = new OpenLayers.Feature.Vector();
responseList.features.push(feature);
this.readChildNodes(node, feature);
// post-process geometry
feature.geometry = feature.components[0];
},
"GeocodeMatchCode": function(node, feature) {
feature.attributes.matchCode = {
accuracy: parseFloat(node.getAttribute("accuracy")),
matchType: node.getAttribute("matchType")
};
},
"Address": function(node, feature) {
var address = {
countryCode: node.getAttribute("countryCode"),
addressee: node.getAttribute("addressee"),
street: [],
place: []
};
feature.attributes.address = address;
this.readChildNodes(node, address);
},
"freeFormAddress": function(node, address) {
address.freeFormAddress = this.getChildValue(node);
},
"StreetAddress": function(node, address) {
this.readChildNodes(node, address);
},
"Building": function(node, address) {
address.building = {
'number': node.getAttribute("number"),
subdivision: node.getAttribute("subdivision"),
buildingName: node.getAttribute("buildingName")
};
},
"Street": function(node, address) {
// only support the built-in primitive type for now
address.street.push(this.getChildValue(node));
},
"Place": function(node, address) {
// type is one of CountrySubdivision,
// CountrySecondarySubdivision, Municipality or
// MunicipalitySubdivision
address.place[node.getAttribute("type")] =
this.getChildValue(node);
},
"PostalCode": function(node, address) {
address.postalCode = this.getChildValue(node);
}
},
"gml": OpenLayers.Format.GML.v3.prototype.readers.gml
},
/**
* Method: write
*
* Parameters:
* request - {Object} An object representing the geocode request.
*
* Returns:
* {DOMElement} The root of an XLS document.
*/
write: function(request) {
return this.writers.xls.XLS.apply(this, [request]);
},
/**
* Property: writers
* As a compliment to the readers property, this structure contains public
* writing functions grouped by namespace alias and named like the
* node names they produce.
*/
writers: {
"xls": {
"XLS": function(request) {
var root = this.createElementNSPlus(
"xls:XLS",
{attributes: {
"version": this.VERSION,
"xsi:schemaLocation": this.schemaLocation
}}
);
this.writeNode("RequestHeader", request.header, root);
this.writeNode("Request", request, root);
return root;
},
"RequestHeader": function(header) {
return this.createElementNSPlus("xls:RequestHeader");
},
"Request": function(request) {
var node = this.createElementNSPlus("xls:Request", {
attributes: {
methodName: "GeocodeRequest",
requestID: request.requestID || "",
version: this.VERSION
}
});
this.writeNode("GeocodeRequest", request.addresses, node);
return node;
},
"GeocodeRequest": function(addresses) {
var node = this.createElementNSPlus("xls:GeocodeRequest");
for (var i=0, len=addresses.length; i<len; i++) {
this.writeNode("Address", addresses[i], node);
}
return node;
},
"Address": function(address) {
var node = this.createElementNSPlus("xls:Address", {
attributes: {
countryCode: address.countryCode
}
});
if (address.freeFormAddress) {
this.writeNode("freeFormAddess", address.freeFormAddress, node);
} else {
if (address.street) {
this.writeNode("StreetAddress", address, node);
}
if (address.municipality) {
this.writeNode("Municipality", address.municipality, node);
}
if (address.countrySubdivision) {
this.writeNode("CountrySubdivision", address.countrySubdivision, node);
}
if (address.postalCode) {
this.writeNode("PostalCode", address.postalCode, node);
}
}
return node;
},
"freeFormAddress": function(freeFormAddress) {
return this.createElementNSPlus("freeFormAddress",
{value: freeFormAddress});
},
"StreetAddress": function(address) {
var node = this.createElementNSPlus("xls:StreetAddress");
if (address.building) {
this.writeNode(node, "Building", address.building);
}
var street = address.street;
if (!(street instanceof Array)) {
street = [street];
}
for (var i=0, len=street.length; i < len; i++) {
this.writeNode("Street", street[i], node);
}
return node;
},
"Building": function(building) {
return this.createElementNSPlus("xls:Building", {
attributes: {
"number": building["number"],
"subdivision": building.subdivision,
"buildingName": building.buildingName
}
});
},
"Street": function(street) {
return this.createElementNSPlus("xls:Street", {value: street});
},
"Municipality": function(municipality) {
return this.createElementNSPlus("xls:Place", {
attributes: {
type: "Municipality"
},
value: municipality
});
},
"CountrySubdivision": function(countrySubdivision) {
return this.createElementNSPlus("xls:Place", {
attributes: {
type: "CountrySubdivision"
},
value: countrySubdivision
});
},
"PostalCode": function(postalCode) {
return this.createElementNSPlus("xls:PostalCode", {
value: postalCode
});
}
}
},
CLASS_NAME: "OpenLayers.Format.XLS.v1"
});

View File

@@ -0,0 +1,53 @@
/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format/XLS/v1.js
*/
/**
* Class: OpenLayers.Format.XLS.v1_1_0
* Read / write XLS version 1.1.0.
*
* Inherits from:
* - <OpenLayers.Format.XLS.v1>
*/
OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class(
OpenLayers.Format.XLS.v1, {
/**
* Constant: VERSION
* {String} 1.1
*/
VERSION: "1.1",
/**
* Property: schemaLocation
* {String} http://www.opengis.net/xls
* http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd
*/
schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd",
/**
* Constructor: OpenLayers.Format.XLS.v1_1_0
* Instances of this class are not created directly. Use the
* <OpenLayers.Format.XLS> constructor instead.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*/
initialize: function(options) {
OpenLayers.Format.XLS.v1.prototype.initialize.apply(
this, [options]
);
},
CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0"
});
// Support non standard implementation
OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0;

View File

@@ -0,0 +1,98 @@
<html>
<head>
<script src="../../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_read(t) {
t.plan(16);
var response = '<xls:GeocodeResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd" xmlns:xls="http://www.opengis.net/xls" xmlns:gml="http://www.opengis.net/gml"><xls:GeocodeResponseList numberOfGeocodedAddresses="1"><xls:GeocodedAddress><gml:Point srsName="EPSG:28992"><gml:pos dimension="2">122650 483904</gml:pos></gml:Point><xls:Address countryCode="NL"><xls:StreetAddress><xls:Building number="1"/><xls:Street>president kennedylaan</xls:Street></xls:StreetAddress><xls:Place type="MunicipalitySubdivision">amsterdam</xls:Place><xls:Place type="Municipality">amsterdam</xls:Place><xls:Place type="CountrySubdivision">noord holland</xls:Place><xls:PostalCode>1079MB</xls:PostalCode></xls:Address></xls:GeocodedAddress></xls:GeocodeResponseList></xls:GeocodeResponse>';
var format = new OpenLayers.Format.XLS();
var output = format.read(response);
t.eq(output.responseLists.length, 1, "Output contains 1 responseList");
var responseList = output.responseLists[0];
t.eq(responseList.numberOfGeocodedAddresses, 1, "Responselist contains 1 geocoded address");
t.eq(responseList.features.length, 1, "1 feature parsed");
var feature = responseList.features[0];
var address = feature.attributes.address;
t.eq(address.building["number"], "1", "Building number correctly parsed");
t.eq(address.countryCode, "NL", "Country code correctly parsed");
t.eq(address.place.CountrySubdivision, "noord holland", "CountrySubDivision correctly parsed");
t.eq(address.place.Municipality, "amsterdam", "Municipality correctly parsed");
t.eq(address.place.MunicipalitySubdivision, "amsterdam", "MunicipalitySubdivision correctly parsed");
t.eq(address.postalCode, "1079MB", "Postalcode correctly parsed");
t.eq(address.street[0], "president kennedylaan", "Street correctly parsed");
t.eq(feature.geometry.x, 122650, "Geometry [x] correctly parsed");
t.eq(feature.geometry.y, 483904, "Geometry [y] correctly parsed");
var responseList = [];
responseList.push('<?xml version="1.0" encoding="UTF-8" ?>',
'<XLS xmlns="http://www.opengis.net/xls" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/xls LocationUtilityService.xsd" version="1.1">',
' <ResponseHeader/>',
' <Response version="1.1" requestID="">',
' <GeocodeResponse>',
' <GeocodeResponseList numberOfGeocodedAddresses="2">',
' <GeocodedAddress>',
' <gml:Point>',
' <gml:pos>-71.4589837781615 41.8317239069808</gml:pos>',
' </gml:Point>',
' <Address countryCode="">',
' <StreetAddress>',
' <Street></Street>',
' <Street/>',
' </StreetAddress>',
' <Place type="Municipality"></Place>',
' <Place type="CountrySubdivision"></Place>',
' <PostalCode></PostalCode>',
' </Address>',
' <GeocodeMatchCode accuracy="100.0"/>',
' </GeocodedAddress>',
' <GeocodedAddress>',
' <gml:Point>',
' <gml:pos>-71.4087296631643 41.8269575002255</gml:pos>',
' </gml:Point>',
' <Address countryCode="">',
' <StreetAddress>',
' <Street></Street>',
' <Street/>',
' </StreetAddress>',
' <Place type="Municipality"></Place>',
' <Place type="CountrySubdivision"></Place>',
' <PostalCode></PostalCode>',
' </Address>',
' <GeocodeMatchCode accuracy="100.0"/>',
' </GeocodedAddress>',
' </GeocodeResponseList>',
' </GeocodeResponse>',
' </Response>',
'</XLS>');
response = responseList.join("");
output = format.read(response);
t.eq(output.version, "1.1", "Version correctly parsed");
var responseList = output.responseLists[0];
t.eq(responseList.numberOfGeocodedAddresses, 2, "2 addresses parsed");
t.eq(responseList.features.length, 2, "2 features parsed");
t.eq(responseList.features[0].attributes.matchCode.accuracy, 100.0, "Accuracy correctly parsed");
}
function test_write(t) {
t.plan(1);
var format = new OpenLayers.Format.XLS();
var address = {
countryCode: 'US',
street: '1 Freedom Rd',
municipality: 'Providence',
countrySubdivision: 'RI',
postalCode: '02909'
};
var request = format.write({addresses: [address]});
var expected = '<xls:XLS xmlns:xls="http://www.opengis.net/xls" version="1.1" xsi:schemaLocation="http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><xls:RequestHeader/><xls:Request methodName="GeocodeRequest" requestID="" version="1.1"><xls:GeocodeRequest><xls:Address countryCode="US"><xls:StreetAddress><xls:Street>1 Freedom Rd</xls:Street></xls:StreetAddress><xls:Place type="Municipality">Providence</xls:Place><xls:Place type="CountrySubdivision">RI</xls:Place><xls:PostalCode>02909</xls:PostalCode></xls:Address></xls:GeocodeRequest></xls:Request></xls:XLS>';
t.xml_eq(request, expected, "XLS geocode request correctly written");
}
</script>
</head>
<body>
</body>
</html>

View File

@@ -103,6 +103,7 @@
<li>Format/SOSGetObservation.html</li>
<li>Format/SOSGetFeatureOfInterest.html</li>
<li>Format/OWSContext/v0_3_1.html</li>
<li>Format/XLS/v1_1_0.html</li>
<li>Format/XML.html</li>
<li>Geometry.html</li>
<li>Geometry/Collection.html</li>