Skip to end of metadata
Go to start of metadata

h. Set up queries - AJAX

We wanted to be able to send off a query to the server and have hte results returned without having to reload the page. This would be beneficial if the user was looking around on the map and didn't want to lose their position when they searched for something.
To do this, we used a technique called AJAX: Asycronous Javascript And XML.
Really all it is, is sending off a request to the server, waiting for a response, then parsing and displaying the result; without reloading the page.
Asynchronous, meaning that multiple requests at once.
Javascript, meaning that it is all prepared on the client side in Javascript
XML, meaning that it communicates with XML.

The XML part of it is the request package that is sent to the server. The server then sends back an XML request package. What will it look like? Well that entirely depends on what the server is and what your request is. It can by anything.
Now to make some sense out of it, we will be using a protocol called WFS (Web Feature Service). It is a protocol for querying geographic data, inserting geographic data, modifying geographic data.
The request is defined by an XML schema (.xsd file) that has the rules for how the request must look.
The request we are using is a "GetFeature" request: this gets us a geographic feature.
So our request is XML in the form of a GetFeature request.

So what will the server send back? Hopefully features... or at least an error. Features are described in XML, called GML (Geographic Markup Language). The response back should be a collection of features: a FeatureCollection.

Ok, so we send XML (GetFeature request) and receive XML (GML feature collection).

Lets look at the javascript that does this:

It's fairly simple if you stand back and look at it. It boilds down to a few lines of code:
geo_xmlhttp = new XMLHttpRequest(); // mozilla
geo_xmlhttp.onreadystatechange = myAjaxProgressFunction; // set the 'listen' method
geo_xmlhttp.open("POST", "http://sigma.openplans.org/geoserver/wfs/", true); // open it up and pass in the values
geo_xmlhttp.send(post); // send it

This will prepare the XML request (getFeature request), send it to the URL "http://sigma.openplans.org/geoserver/wfs/" over "POST" and then hand off control to "myAjaxProgressFunction()" which will wait for the response.
The myAjaxProgressFunction() function gets called over and over until finally a response arrives. Then, if everything is ok, the response's readyState will be '4' and the status will be '200'.

In the example method above, we just print out the response text.
To parse the response using XML DOM objects (what you really need to do to get useful information) you need to call geo_xmlhttp.responseXML.

The request object has to be set up differently depending what browser you are using. That is why I used a separate method called getXML(). In that method I ask the browser who it is:

Ok, so we have our AJAX system set up to send off XML getFeature requests and expect back GML FeatureCollections. What does a typical GML FeatureCollection look like for a request? It looks like this:

In the response above there is only one <gml:FeatureMember>, but it is possible there will be many more. In fact if you search the GNIS database for 'vancouver' you will get 44 results.

Narrow the search with Countries

We now have a system that will search the GNIS database for geographic location. Now lets search for geographic locations inside specific countries, to help narrow our search.
To do this I added an extra form field for the country name, and made a second getFeature request XML function that searches for "location AND country".
Here is what the request XML for the two field search looks like:

For more information on setting up Filters, look here: http://www.opengeospatial.org/docs/02-059.pdf
(yes it's a spec, sorry)

Handling the Response

We now can send a request off, with multiple parameters, and get a response back. Next we have to parse the response into something nice to look at.
To do this we need to walk the DOM object sent back in the response.
(the DOM object is the geo_xmlhttp.responseXML object: a bunch of XML)
What this really is, is digging through the XML and finding the information we want. It looks like this:

This will walk the first level of the returned XML document and look for the tag "FeatureCollection").

To do this in IE and Mozilla, I had to write a separate function that would attach the namespace of the tag to the tag name for Internet Explorer:

Mozilla can search for tags regardless of the namespace, IE needs the namespace to be specified. To call the method to search for a "FeatureCollection" tag, it looks like this:

An array of elements is returned from the getElements function. We know there is just going to be one FeatureCollection element, so we grab the first, 0.

Now, we want to run through the XML response and pull out all the 'FeatureMembers'. They are the results that the WFS server found, and is what we want to give back to the user.
Each FeatureMember has a handfull of information:

In order to get to this information, we have to dig a little deeper in the XML response to get at it. Here are the few lines that do just that:

Here is a pseudo view of the returned XML response for the FeatureCollection so you can see the hierarchy:

What we did was first get the 'FeatureCollection', then get the child of that called 'FeatureMember', then get the child of that called 'gnis', and then grab all the information from the children in 'gnis'.

You can use the getElements method to walk a normal HTML document too. Give it a try, just put in a blank prefix.

At this point, we have sent a request to the WFS server, gotten a response, and parsed the response. In the end we have it printing out lines that look like:
Vancouver is a city in British Columbia, Canada
Vancouver Island is an island in British Columbia, Canada
Vancouver Island Ranges are mountains in British Columbia, Canada
Vancouver is a city in WA, United States
Vancouver is a city in TN, United States
Vancouver Junction is a city in WA, United States
Vancouver is a rock in New Zealand, New Zealand
Vancouver Arm is a bay in New Zealand, New Zealand
Vancouver Beach is a beach in Western Australia, Australia

I did some extra formatting to look at the 'type' of the feature and change the english response to better fit. I also sorted by city name first, everything else after.

The next step is to prepare for the user clicking on the the search result and having the map zoom to that location (pretty sweet!).
That is covered in a later section. First we need a map!

TROUBLESHOOTING

Getting errors when you send off your XML getFeature request? If you are using a Mozilla browser, it won't allow you to send content to a remote server. Sigh, but this is good! ... for security reasons.
To get around this, you have to put your page in the same spot where your WFS server is. This isn't actually getting around the problem, it is what you have to do.
We found that we also needed to have the server use the same port.
I encountered this problem when I was testing the page on my local machine and sending the request off to the remote server (GeoServer). I just moved the page to the server and tested from there.

SUMMARY

Created a form with two entries: 'geographic location name' and 'country'.

Took the users input from the form and build up an XML request (GetFeature request).

Created an XMLhttp request object.

  • Put the correct URL in the object:
  • Added the getFeature request XML to the object
  • Sent the object off to the server

Waited for a response from the server.

Once the response was received, we parsed the results by walking the XML structure (getElements() function).

Displayed the results to the user.

>>Proceed onto the next step, Step 4: Setting up a Map >>

Labels: