|
This article was previously published on GeoChalkboard, and has been reproduced here with permission. It was originally published as two separate articles which have been combined here to emphasize their relevance to the geospatial web. GeoChalkboard is published by Geospatial Training Services who provide a range of geospatial web courses.
As a GIS web application developer you have many choices when it comes to developing web based mapping applications. The new JavaScript APIs including ArcGIS Server, Google Maps, Bing Maps (still can’t get used to calling Virtual Earth by its new name), OpenLayers, and others have opened up a treasure chest of opportunities for developers. These JavaScript APIs excel at quickly accessing and displaying geographic data to your end users. But there are many times when you need to display additional non-geographic data in your applications and this data can come in many formats including database tables, JSON, XML, CSV, images, and others. This data may be displayed in a variety of user interface components including grids, trees, combo boxes, image galleries, and others. Dojo not only provides the user interface widgets for displaying the data, but also a data abstraction layer for accessing data in various formats.
Accessing Multiple Data Formats with the Dojo Data API
Dojo provides extensive utilities for reading and writing data in various formats through its Data API. The Data API is actually composed of four abstract API’s including the Read, Write, Identity, and Notification APIs. These abstract APIs are implemented by various core implementations called stores that read specific dataset types including JSON, XML, CSV and web services from Google, Flickr, and others. For example, the GoogleSearchStore is a core implementation of the abstract Read and Write Data APIs that can be used to perform a search against Google’s Search Service. In the next few posts we will examine several of the core implementations of the Data API including stores used to read data in JSON, XML, and CSV formats. For today though we’ll simply get a high level overview of the abstract Data APIs.
Dojo.data provides a uniform data access layer that removes the concepts of database drivers, service endpoints, and unique data formats. All data, whether the format be JSON, XML, CSV, or something else, is represented by items (rows in database terminology) and attributes (columns in database terminology) of an item. These items are returned via fetches or queries against a data set. The basic implementation of dojo.data gives you access to ItemFileReadStore which provides read access to JSON format data and ItemFileWriteStore which provides write access to in-memory JSON format data. Additional stores including XmlStore, CsvStore, and endpoint specific stores for Flickr, Google, Amazon, and others are provided through the DojoX project (dojox.data). Obviously you will want to do something with the data once it has been retrieved. Normally you’ll want to display the data in some way. Dojo widgets (called dijits) such as grids, trees, combo boxes, and others are data store aware and can easily be hooked into your data store.
Data can be stored either locally or remotely. It is treated the same either way. The Data API also removes the need for you as a programmer to acquire boilerplate code that retrieves data, writes updates to the server, maintains synchronicity with the server, and handle variable formats. Dojo provides a standardized way of interacting with whatever data source you need to work with. In the Data API, a data store is the main object for each implementation and is created as a driver for one and only one dataset. For instance, the ItemFileReadStore object is a core implementation of the Data API which is used to read data in a JSON format.
In the figure below you will see a visual representation of the Dojo Data API. As you can see the Dojo.Data API acts as an abstract layer containing the Read, Write, Notify, and Identify API’s. The Core Data API implementations are know as stores and they handle a specific type of data whether that be XML, JSON, CSV, or some other data type. In any case all data stores provide a common interface for interfacing data that is stored either locally or remotely.
As I mentioned previously the Dojo Data API is actually a set of four APIs which are interfaces or abstractions. They are not implementations, but rather blue-prints for a core implementation of the APIs. For example, ItemFileReadStore is a core implementation of the API and implements the Read and Identity APIs. A core implementation only implements the APIs it needs. So, let’s briefly discuss each of the abstract data APIs.
Read
The Read API is implemented by all data stores. Obviously you need to retrieve data before you can do anything else so it is essentially a prerequisite for all other operations. Some data stores are read-only type objects so they need to implement this API as well so that they can read data and pass it off for display.
Identity
The Identity API is very similar to the Read API, but provides a few additional capabilities such as the ability to perform random access of an item within a dataset. Identity also returns unique data items which is important when using certain user interface Dijits such as combo boxes, filtering selecting, and tree dijits which need unique items.
Write
The Write API also builds on the Read API by providing additional capabilities for creating, updating, and deleting items from a store. The in-memory copy of data is changed, but the Write API can also handle the synching of datasets between in-memory copies of the data and their data sources.
Notification
The Notification API builds on the Read API and complements the Write API. It provides a unified interface for responding to create, update, and delete events.
Reading JSON Data with Dojo
We have just covered the high level details of the Read, Identity, Write, and Notification APIs that together comprise what the Dojo Data API. These abstract APIs are implemented by various core implementations called stores that read specific dataset types including JSON, XML, CSV and web services from Google, Flickr, and others. Today we’re going to discuss ItemFileReadStore which is Dojo’s core implementation for JSON format data.
What is JSON?
JSON or JavaScript Object Notation is a text based, lightweight data-interchange format that is easy for a human to read. In addition, from an application development standpoint it’s easy to write and parse. JSON is typically preferable to XML if you have a choice. Since the format of JSON is close to what you find with JavaScript objects it requires less translation than XML and has been clocked at as much as 100 times faster than XML in a browser environment (Dojo: The Definitive Guide). To see an example JSON file please click here.
ItemFileReadStore
Dojo uses the ItemFileReadStore and ItemFileWriteStore data stores to work with JSON format data. ItemFileReadStore implements the Read and Identity APIs and is used to read JSON data while ItemFileWriteStore is used to write JSON format data and implements all four of the Data APIs. We’ll be discussing ItemFileReadStore in this post.
ItemFileReadStore is the specific data store implementation for reading JSON data. In addition to implementing the Read and Identity APIs, ItemFileReadStore also contains additional implementation features including a specific data format, query syntax, means for deserializing attribute values, identifiers for items, and others. Now let’s look at an example of the data format expected by ItemFileReadStore.
ItemFileReadStore requires that JSON data follow a specific structure which is outlined via a code example shown in the figure below.
The identifier property points to the identifier attribute in items. An optional label property points to the label attribute. Finally, the data itself comes in items, which is an array of attribute/value pairs. The test data shown in the example was taken from a JSON file containing wildfire information. Ultimately each of these wildfires is plotted to our sample Google Maps application as a marker. Each wildfire is given a unique numeric identifier and the label is simply the latitude and longitude coordinates combined. The items are a collection of attribute/value pairs listing information about the specific fire including the coordinates, date, time, satellite that identified the fire, and the confidence value.
Creating ItemFileReadStore
Instances of ItemFileReadStore can be created in your code either declaratively or programmatically. In either case, the end result is the same in terms of what the user sees. Declarative creation is easily accomplished through the use of dojoType as seen in the code below. The ‘url’ attribute is used to point to the location of your JSON format file. Here it is assumed that the file is located in the same folder as your application, but this could also be a fully qualified url. You will also want to assign an ID to the instance so that it can be referred to later in your application.
Programmatic creation of ItemFileReadStore is accomplished using a constructor as seen below. Here we are passing in the url to our file. The end result is a new instance of ItemFileReadStore which is referenced by the variable itmFileReadStore.
Applying a Query
You can apply a query to an instance of ItemFileReadStore to create a subset of the data returned by ItemFileReadStore. The Fetch() method can be used to execute a query against the data store. The query should take the format you see in the figure below where the word ‘query’ is followed by a colon and then the query attributes inside curly brackets.
You can also specify additional queryOptions of ignoreCase and deep. In addition to providing the ability to query a data store, the Fetch method also provides a number of callback for handling the return events.
ItemFileReadStore.Fetch provides the ability to query the data store similar to a SELECT statement in SQL. To apply an ‘AND’ condition to the query you simply separate the items with a comma which serves as an implied ‘AND’. In the code example below we are querying for all items with a satellite value of ‘T’ AND a date of ‘03312009’.
As I mentioned earlier this is only a semi-standard version of SQL so you can’t use OR, NOT, set operations, numerical comparison operators, or joins. You are pretty much limited to ‘AND’ conditions supported by wildcard operators. The wildcard operators include an asterisk for matching multiple characters and a question mark for matching a single character. Furthermore, you can also use the ‘ignoreCase’ and ‘deep’ queryOptions. By default both options are set to ‘false’. Ignore case is self descriptive so I won’t go into detail on this other than to say that setting this value to ‘true’ will ignore upper and lower case characters that match the query. The ‘deep’ option triggers a query of all items and child items instead of only items at the root level.
Callback Functions
Fetch also provides the ability to call a handful of callback functions in response to various events. The syntax for each event handler is the name of the handler followed by a colon and then the name of the function that should execute in response to the event. The four event handlers include onBegin, onComplete, onError, and onItem. Most of these handlers are self descriptive, but the onItem event requires further explanation. The onItem handler is fired once for each item returned by the query. This is typically specified when you need to explicitly perform some type of operation on each item that is returned. Perhaps you’d like to do some additional filtering or attach a custom attribute to the item depending upon the value. Each event handler is just a specific JavaScript function run in response to the event. The code examples below provide more details on the callback function that are available.
Search by Identifier
As you’ll recall from earlier in the discussion an ItemFileReadStore object implements the Identity API as well as the Read API. The Identity API provides for the implementation of a fetch by an identifier through the fetchItemByIdentity method. The identifier is a unique value and the fetchItemByIdentity method can search through your JSON file or stream for a specific value. There are two event handlers that can be used to process the item or handle any errors. onItem is used to process the returned item while onError is used to process errors. This process is described in the figure below.
About Eric Pimpler
This article was written by Eric Pimpler at GeoSpatial Training Services. Geospatial Training Services provide a
range of geoweb courses.
 |