Saturday, 21 September 2019

MapGuide 4.0 showcase: JSON that's easier to work with.

If you've ever worked with the HTTP-based mapagent API, you should be aware that most of the APIs responses in the mapagent generally come back in 2 forms:

  • XML
  • JSON
However, if you ever look at the JSON responses, you'll be accustomed to dealing with ugly monstrosities like this (eg. A JSON version of a Layer Definition):

Or heaven forbid, you want to explore the structure of a Feature Source and so you need the JSON version of a FDO feature schema:

Good luck trying to parse and comprehend that!

Why is the JSON so horrible? The answer is XML is the canonical response format for all non-image/binary mapagent operations (MapGuide Open Source's inception was in 2004 after all, when XML was king and JSON probably didn't exist yet), so the JSON version is a literal translation of whatever its XML form would be. While there is nothing wrong with that, the way this JSON translation was done is the most lowest-common-denominator approach:
  • Treat every XML element as a JSON array.
  • Treat every XML element text body as a JSON string.
As a result, as evidenced by the above screenshots that means that all JSON responses are nothing but a series of JSON arrays (of possible more JSON arrays) of strings.

But there is a reason for such laziness. The JSON translation knows nothing about the content model of whatever XML it's trying to translate, so it really has no choice in the matter. Such content models are defined in the various XML schemas that are shipped with MapGuide. But working with XML schemas in C++ sounds like a nightmare in and of itself, so there is another way to determine the content model: Just manually hard-code the list of all possible XML xpaths that are:
  • Repeating (ie. Should be converted to actual JSON arrays)
  • Not a string
Using the existing XML schemas as the reference, this list only required a one-off painstaking translation of this xpath list. The end result isn't exactly pretty, but it gets the job done. With this hard-coded list now in our JSON converter, it means we now have the means to output JSON that is much easier to comprehend and intuitive! 

For MGOS 4.0, for any mapagent operation that returns JSON, if you specify VERSION=4.0.0 and CLEAN=1 in the request parameters you will now get a JSON format that actually makes sense!

Now for some mapagent operations, finally having a "clean" JSON version still isn't enough because the clean JSON response is still mostly clunky and unusable. Consider the FDO feature schema example. The original JSON version is an unworkable monstrosity, and the "clean" version would've just been lipstick on a pig because at the end of the day, it is still a literal JSON translation of an XML schema! 

So as a result, for this set of APIs, a new simpler XML response format is introduced for schema and class definitions by including SIMPLE=1 to your VERSION=4.0.0 request:

From which its JSON equivalent (I hope you'll agree) is much more easier to comprehend!

There is another class of operations that have received a similar treatment. Operations that return geometric/feature data. Consider the XML form of selecting features (the ugly schema section collapsed for brevity):

This is what the "ugly" JSON version would've looked like (schema parts again collapsed for brevity). 

Even if we prettied this up with content-model-aware conversion, the JSON is still mostly unremarkable. Because, if we're serving JSON feature data out to clients, then there's really only one format we should care about supporting:

GeoJSON is the de-facto format for serving out JSON-based feature data, and is universally supported by any mapping/GIS product/tool/library/viewer worth a damn, so if we have the opportunity for MapGuide to return clean JSON data for geometries/features, forget about the literal conversion from XML approach! Just go ahead and make GeoJSON output a first-class citizen

So for MGOS 4.0, if you run any mapagent operation that returns geometry/feature data and you ask for VERSION=4.0.0 and CLEAN=1 you will now get GeoJSON!

Which (due to GeoJSON's ubiquity) can be plugged directly into your web mapping library of choice for display if you so choose.

If you are building your own server-side MapGuide applications with the MapGuide Web API, there's a new MgGeoJsonWriter class is available for you to convert MgFeatureReaders to GeoJSON data.

With MapGuide Open Source 4.0, JSON support is no longer an afterthought, it's actually usable!

No comments: