Thursday, March 27, 2014

Microsoft 70-480: Serialize, deserialize, and transmit data

Exam Objectives


Binary data; text data (JSON, XML); implement the jQuery serialize method; Form.Submit; parse data; send data by using XMLHTTPRequest; sanitize input by using URI/form encoding


Quick Overview of Training Materials

Cross-browser JSON Serialization in JavaScript
Using XMLHttpRequest (Mozilla Dev Net)
4.10.19.6 Form submission - w3.org HTML5 spec

ArrayBuffer is a data type that is used to represent binary data in JavaScript.  It is not possible to read and write to an ArrayBuffer directly, instead this is done with a view object. The ArrayBufferView is an abstract interface that holds information shared among the various typed array views. Typed arrays can be of signed or unsigned Int8, 16, and 32, as well as Float32 and 64, and "clamped" unsigned Int8 (which replaces the CanvasPixelArray). Typed arrays can be constructed directly (which creates a new ArrayBuffer) or they can be created as views to an existing ArrayBuffer. This code snippet illustrates the difference:

//create a buffer and assign an Int32 view
var ab = new ArrayBuffer(1024); // 1024 byte ArrayBuffer
var abInt = new Int32Array(ab); 

//create an Int32 Typed array with twenty array elements
var intAr = new Int32Array(20); 

This fiddle demos the various Typed Arrays in use (and how they can get weird if you mix and match...):


The DataView interface provides low level access to ArrayBuffer data. DataView objects can read and write to the ArrayBuffer in any of the types described above for Typed Arrays. A byte offset is used to indicate where in the stream to access data. This Fiddle demonstrates the concept:



Finally, a blob object is created by combining ArrayBuffers, TypedArrays, strings, or other blobs.  The only way to read data from a blob directly is with a FileReader object. The file reader will start reading the blob with the readAsXXX (where XXX is ArrayBuffer, BinaryString, DataURL, or Text) and fire an event "loadend" when the blob is completely read.  The Mozilla Dev Net example sets a listener to this event with an anonymous function set to do whatever it is you want to do with the contents of the blob. Here is a fiddle demonstrating a blob with strings:



Using binary data with XMLHTTPRequest (XHR)


Having examined the binary types, it's simple to use the XHR.responseType property to transmit and receive binary data.  This property can be set to either "arraybuffer" or "blob", after which the XHR.response will be an object of that type.  So if we want an arraybuffer that we want to read as a byte array (Uint8), we do the following:

xmlhttp.open ( <method>, <content>, true);
xmlhttp.responseType = "arraybuffer";

// in our event listener for readystatechange when
// xmlhttp.onreadystatechange == 4 & xmlhttp.status == 200
var arr = new Uint8Array(xmlhttp.response); //NOT responseText
// the variable arr is now a byte array view on the underlying arraybuffer in xmlhttp.response

Using a blob is similar:

xmlhttp.open ( <method>, <content>, true);
xmlhttp.responseType = "blob";

// in our event listener for readystatechange when
// xmlhttp.onreadystatechange == 4 & xmlhttp.status == 200
var blob = xmlhttp.response; //response is already a blog so no need for new Blob([]).

The XHR.send() method is also capable of sending Blob, ArrayBuffer, and File data.

Serializing Forms, JSON, and XML


The jQuery.serialize() method will serialize form data into a URL string in the form of name1=val1&name2=val2&... To use, simply call the method on a selected form: $( "form" ).serialize(). The method only serializes the selected form elements, so selecting a subset of the controls in the form will result in only those controls being serialized.  Checkboxes with the same name and multi-selects are serialized like name=val1&name=val2... Where 'name' is the common name of the controls.  The jQuery API includes a demo.

Serializing and deserializing JSON is done using the JSON.stringify (serialize) and JSON.parse (deserialize) function.  A simple way to see these in action is with the browser console. Below I show an example using Chrome with some sample JSON from the JSON Wikipedia article. A variable 'text' is created with 


Parse can handle multiple objects at a time, they just have to be in an array, like '[{name:val},{name:val},{name:val}]'.  Using data from Finra for bonds, we can construct very complicated JSON strings and objects (to get the JSON, open up 'network' in the browser developer tools, find 'bondSearch.jsp', and look in the response):
This is where the data came from. I cut out the {B: {"Columns": and a section at the end about {"Rows"...} cause it was giving me fits. 

Subset of the data, these searches usually return at least 20 results... this is four.

Data parsed into JSON objects; two are expanded.

Finally, the XMLSerializer object will let us convert DOM trees into strings, and the DOMParser object will let us create DOM trees from a string (using a MIME type).  By way of a demonstration, in the browser console, enter the following commands in sequence:

// creates new serializer object
x = new XMLSerializer 

// creates new parser object  
dp = new DOMParser      

// serializes the current page into a 
// string and assigns it to dtext
dtext = x.serializeToString(document) 

// converts string back into HTML DOM tree
dp.parseFromString(dtext, "text/html")

Should look something like this:



Encoding and Decoding URIs


When using an HTTP GET, or a POST with the MIME type of "application/x-www-form-urlencoded", data sent in the query string must be encoded using encodeURIComponents().  Mind you only encode the query string with this method, as it will encode ALL characters, including slash and colon (and thus will break the overall URL).  If you want a valid overall URL, you use encodeURI().  Taking another look at the Finra data, we can see in the form data (sent as part of the request) that the raw query string is URI encoded:


If we "view parsed" and then "view decoded", we will see that the query is actually a JSON string:


Going from a form to JSON to an encoded URI string would look something like this (using jQuery, borrowed most of the code from this article):

// grab the form elements into an array
var array = jQuery(form).serializeArray();

//initiallize an object
var json = {};

//now we build a JSON object from the array
jQuery.each(array, function() {
     json.[this.name] = this.value || '';
});

//serialize our JSON object into a string
var jstring = JSON.stringify(json);

//URI encode the json string
var uriJson = encodeURIComponent(jstring);

//send it on its way with AJAX
xmlhttp.open("POST", url ,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(uriJson);




Form submission and encoding


According to the spec, there are three possible encoding types for form data:
  • application/x-www-form-urlencoded - expects form data to be in typical URL query string format. Most forms use this.
  • multipart/form-data - the standard for this type [RCF2388] states it is intended for multiple representations other than HTML and transport means other than SMTP (email) and HTTP. 
  • text/plain - intended to be human readable (and thus might not be appropriate for machine interpretation). This will omit the '&' between fields.
On "POST" requests, this is set in the request header called "Content-type", as can be seen in the example above.  Using the enctype attribute on the form element is what sets which encoding type will be used. If this attribute is omitted, application/x-www-form-urlencoded is used by default. So if you wanted to use the multipart/form-data encoding, your form element would look like this:

<form action="processForm.php" method="post" enctype="multipart/form-data">


No comments:

Post a Comment