MSON: JSON for Miva

Processing...
MSON:  JSON for Miva

I like working with Miva Script, but it does have a few downsides. For one thing, it's a very verbose language. This statement:

<MvASSIGN NAME="l.a" VALUE="{ l.b + l.c }">

-- takes 43 characters, whereas in most programming languages it looks more like:

a = b + c;

-- which takes 10. Every character you enter is another opportunity for a typo; so I'm always looking for shortcuts to make my code more concise.

When I need to create an object with several members, I used to write a stack of assignment statements, such as this example from one of my shipping modules:

-- which would be followed by a call to Basket_Charge_Insert(). Recently, I created an object-building function that lets me rewrite the code like this:

The format is a bit cryptic with all the quotes and other delimiters, but it's still less typing. Would you like to have a copy of Object() for your own use? Here you go:

The format that Miva Script uses for serializing data is plain text, comma-delimited. It's flexible enough to allow some white space for readbility. It's conceptually similar to JSON, which makes it worthy of the name "MSON:" Miva Script Object Notation.

If you run miva_array_serialize() on the shipping-charge object I just created, you'll get back a string that looks like this:

:amount=12.34,:descrip=Shipping%3A+My+shipping+module,:disp_amt=12.34,:module_id=123,
:tax_exempt=0,:type=SHIPPING

It's a comma-delimited list of name-value pairs, or maybe "path-value pairs" is a better description. The part before the equal sign is the member name that specifies the location of the data. The part after the equal sign is the value of the data. Note that string values may need to be URL-encoded (using the Miva built-in function encodeattribute()) in case they contain any of the reserved characters such as the comma and colon. Letters and digits are safe, and don't need to be explicitly URL-encoded. White-space characters can be added after the commas, and in some other places as well, for readbility.

In the above example, each path is a colon and a member name. But this notation works for arrays too, and for more complex structures. For instance, here's the serialization of an array containing a couple of BasketItem objects. It's an array of two elements, each of which is an object with a lot of named members. This data came from the page template, so it's loaded up with things like formatted_price that aren't in the DB table.

Each item has a member named :options, which itself is a nested array of objects about the sizes and colors of the item, copied from the BasketOptions table. The MSON notation gives the complete path for each piece of data; for instance, the price of the 3rd option of the 2nd item has the path [2]:options[3]:price.

By the way, serialization and deserialization work fine on single values; they're not just for arrays and objects. For example, if you serialize the number 12345, the result is the string =12345. The path in this case is empty, since the value has no elements or members.

Serializing an empty string returns an empty string, and the same is true for de-serializing. I think earlier versions of the VM used to return a single equal sign when they serialized an empty string. Deserializing a string consisting of a single equal sign still works, and returns an empty string.

Note that when you serialize an array or object, elements or members that contain the empty string will be completely dropped from the result. This saves some space, and doesn't have much effect on results, since in Miva Script, a variable containing an empty string is largely equivalent to one that hasn't been assigned any value.

So we have this nice notation that's already supported by the language. It's more verbose than JSON, but it does have a few advantages. It can handle sparse arrays, and arrays that start with element number 1 instead of zero, which JSON can't do. And it shows you the complete path for every piece of data, instead of requiring you to count brackets to figure out where something is stored.

Besides serializing data, what's it good for? The Object() function comes in handy from time to time. And whenever I'm working on a Miva module or script, I find it very helpful to put debugging messages in the code that display data in this format. I've written a function that will serialize a variable, clean up the data a bit, and put in the delimiter of my choice. For debugging, I write MvEVALs that use this function to display data on my screen in MSON format.

I usually use a semicolon and a space as the delimiter. The semicolon helps with clarity, since it doesn't often occur in the data; and the space allows my browser to break long lines to fit on the screen. When I want more readability, I use a <br/> tag as the delimiter, to put each path-value pair on a separate line of the screen, as in the above BasketItem example.