In addition to data services, the DataPortal offers Geo API services. These RESTful services allow you to retrieve data and perform spatial analysis via HTTP calls.
Service Output
Service output is standardized for all API service. Format for all REST services comes in two flavors set by the format paramater: XML or JSON. Each return is essentially a XML or JSON representation of a record set.
XML output looks like this:
<rows total-rows="2">
<row>
<column name="column_1">Column Value</column>
<column name="column_2">Column Value</column>
</row>
<row>
<column name="column_1">Column Value</column>
<column name="column_2">Column Value</column>
</row>
</rows>
The XML container tag is “rows”. The “rows” tag contains child “row” tags, one for each record returned. Note the “rows” tag has a “total-rows” property, which indicates the number of rows returned by the query. Each “row” tag has any number of child “column” tags. The “column” tag represents a field or column in the return record set, with the “name” property being the name of the field or column. The value of the “column” tag is the value of that column for that record.
If your query returns no records, the XML response is this:
<rows total-rows="0"/>
JSON output looks like this:
{"total_rows":"1","rows":[
{"row":{"column_1":"column value", "column_2":"column value"}},
{"row":{"column_1":"column value", "column_2":"column value"}}
]}
Essentially, there’s a “total_rows” value and then a parent “rows” element containing a series of “row” elements, one for each record returned. Each “row” element contains a comma delimited column:value pairs. This format is easily digested by a Javascript eval().
If your query returns no records, the JSON response is this:
{"total_rows":"0","rows":"row"}
If your query creates an error, you will recieve an XML error message that looks like this:
<error_handler> <error> <error_message>Error message.</error_message> </error> </error_handler>
As the service return is text, you can perform a simple text string search for “<error_handler>” in the result to check and see if you’ve got problems. If you need to do some serious debugging, let us know and we can help.
Customizing Fields and Parameters
Many of our Geo API services offer you the ability to set custom parameters and fields for your query. We do this because (a) we don’t know what you want, and (b) we’re not going to write web services to handle every request. By keeping the services generic we maximize code reuse and interoperability.
The parameters argument lets you set additional parameters for the query as you would in a SQL where request. For example, suppose you are doing a point buffer and you want to buffer your point by 500 feet and return the voting precincts in that buffer. But suppose you also want to only return voting precincts in the buffer where the precinct (precno) number is greater than 100. Simply add that as a parameter (URL encoding left off here for readability):
parameters = precno > 100
If you don’t need additional parameters, simply leave the parameters argument empty.
The fields argument allows you to specify what fields you would like returned. You can also use the fields parameter to change the field name used in your return. For example (URL encoding left off here for readability):
fields = precno as precinct_number, cc as county_commissioner_district
One of the really cool things you can do with the fields argument is return geometry. You can return geometry as KML, GML, WKT, or SVG. Here are some exampes:
KML fields = askml(the_geom) as the_geom GML fields = asgml(the_geom) as the_geom WKT fields = asewkt(the_geom) as the_geom SVG assvg(the_geom) as the_geom
There are a number of things to note here. First the_geom is the name of the geometry column in all of our geotables, hence the (the_geom) argument. The second thing to note is the return value is in the projection of the geotable (which you can find out with the List Layers web service). If you want it in a different projection, you would need to use the transform option, as seen here:
KML projected to SRID 4326 fields = askml(transform(the_geom, 4326)) as the_geom
4326 is the SRID we want the data returned in. So, in this example, we want the geometry converted to 4326 (decimal degrees) and then returned as KML.
Consuming with PHP
First let’s take a look at consuming a web service with PHP. Here’s an example of a feature overlay:
# Set the web service parameters.
$params = array(
'fields' => 't.precno, t.cc',
'from_geotable' => 'tax_parcels',
'to_geotable' => 'voting_precincts',
'parameters' => "f.pid = '11111111'",
'format' => 'xml'
);
# Set the base URL of the web service.
$base = 'http://theurl/ws_geo_featureoverlay.php';
# URL encode the parameters.
$query_string = "";
foreach ($params as $key => $value) {
$query_string .= "$key=" . urlencode($value) . "&";
}
$url = "$base?$query_string";
# Get the return results.
$result = file_get_contents($url);
That code gets the return results, in this case in XML, and assigns them to the $results variable. Note that the file_get_contents is only available in PHP 5.x or higher. PHP 4 users will have to use the CURL library.
Now that we’ve received web service output, let’s process it.
# Check for error
if (stripos($result, "error_handler") != false) {
echo "Cap'n, we have an error!";
}
# Otherwise process result
else {
$xml = new SimpleXMLElement($result);
# Check number of returned records
if ($xml->rows['total-rows'] = 0) {
echo "No records found!";
}
else {
echo "Total Rows: " . $xml['total-rows'] . "<br />";
foreach ($xml->row as $row) {
echo "Row <br />";
foreach ($row->column as $column) {
echo $column['name'] . ": ";
echo $column . "<br />";
}
}
}
}
First, we checked for an error message. If no message was found, we load the return result into a SimpleXMLElement. We then check to see if any records were returned. If they were, we loop through each row and then each column in each row and echo the result. The result looks like this:
Total Rows: 1 Row precno: 201 cc: 3
For some handy tutorials on XML processing with PHP, check out this article by IBM.
Consuming with .NET
With .NET, connecting to a REST service is about the same amount of work as connecting to a SOAP service. Instead of creating a web proxy, we’ll just use a function to build a url to the web service.
Private Function wsListLayers(ByVal geotable As String, ByVal format As String) As String
Dim strURL As String = "http://theurl/ws_geo_listfields.php"
strURL &= "?geotable=" & Server.UrlEncode(geotable)
strURL &= "&format=" & Server.UrlEncode(format)
Return strURL
End Function
Here are callout the List Fields web service to get a list of a geotable. Now we can call the function and process the results.
Dim strURL As String
Dim xmlDoc As New System.Xml.XmlDocument()
Dim mylist As System.Xml.XmlNodeList
Dim row As System.Xml.XmlNode
Dim node As System.Xml.XmlNode
Dim i As Integer
'Load the service as a XML document
strURL = wsListLayers("polling_locations", "xml")
xmlDoc.Load(strURL)
'Process the return
If xmlDoc.GetElementsByTagName("error_handler").Count > 0 Then
Response.Write("Dude we bombed.")
ElseIf xmlDoc.GetElementsByTagName("row").Count = 0 Then
Response.Write("Dude we gots no records.")
Else
mylist = xmlDoc.GetElementsByTagName("row")
For Each row In mylist
Response.Write("Row " & i & "<br />")
For Each node In row
Response.Write(node.Attributes.Item(0).Value & ": " & node.InnerText & "<br />")
Next
i = i + 1
Next
End If
The output will look like this:
Row 0 field_name: gid field_type: int4 Row 1 field_name: objectid field_type: int4 Row 2 field_name: precno field_type: int4 Row 3 field_name: name field_type: varchar Row 4 ....
Consuming with JavaScript
JSON, or JavaScript Object Notation, is a lightweight, human-readable interchange format. JSON has a number of advantages over XML when consumed with JavaScript:
- It’s extremely easy to create and use.
- It’s fast. Its smaller size makes for quicker transport and process.
- It’s a native JavaScript data format, making processing with JavaScript extremely easy.
While you can process XML output with JavaScript via the DOM, JSON processing with JavaScript is much easier. Let’s look at a consuming a web service. Note that we’re taking advantage of the excellent jQuery JavaScript library.
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(document).ready(function(){
$.getJSON("http://theurl/ws_geo_listfields.php?geotable=voting_precincts&format=json",
function(data){
$.each(data.rows, function(i, item){
$('#results').append(item.row.field_name + ': ' + item.row.field_type + '<br />');
});
});
});
</script>
<div id="results">Fields:<br /></div>
Here’s we’re calling the List Fields GEO web service when the document is ready to process an AJAX request. If the data is successfully loaded, for each row in rows it appends the field name and type to a DIV tag with an ID of ‘results’.
The output will look like this:
Fields:
gid: int4
objectid: int4
precno: int4
cc: int4
school: int4
jud: varchar
zone: int4
area: numeric
len: numeric
the_geom: geometry
You can also call JSON with an optional callback parameter to be returned JSONP. This lets you get around the cross site scripting security in most browsers. For example, if you put this argument at the end of your REST URL:
&callback=myfunction
Then the return will look like this:
myfunction({"total_rows":"1","rows":[
{"row":{"column_1":"column value", "column_2":"column value"}},
{"row":{"column_1":"column value", "column_2":"column value"}}
]})
Then all you’ll need to do is create a myfunction function on your page to handle the return:
function myfunction(data) {....}
For more information on JSON and using it with other languages, check out json.org.
Consuming with VB6
The easiest way to consume REST services from VB6 is to use the Internet Transfer Control (IE Control).
'Assuming you have built your REST URL and called it restURL and your IE control is called iNet Dim getXMLDoc as String ' cancel any pending operation and set protocol to HTTP iNet.Cancel iNet.Protocol = icHTTP ' get the XML getXMLDoc = iNet.OpenURL(restURL)
getXMLDoc now has the service XML output. To parse the XML, they just need to use the XML
DOM for working with XML in VB (Project > References, check “Microsoft XML, v4.0″).
General Tips
- Most Mecklenburg County GIS data is in SRID 2264, or NC State Plane NAD83 feet. The most popular thing to convert it to would be 4326 (WGS84) or 900913 (web mercator).
- If you use Firefox and Firebug for AJAX debugging, this bit of code for jQuery will write AJAX error messages to the console: $(document).ajaxError(function(){ if (window.console && window.console.error) { console.error(arguments); } });

Comments
Leave a comment Trackback