Data-Oriented Mashup Techniques
Data can be mashed together in-process or out-of-process. These two domains typically equate with a web browser and a remote server application, respectively. Many times data will be mashed in a hybrid approach using both in-process and out-of-process techniques.
This section discusses in depth some of the techniques used for both in-process and out-of-process data mashups.
Mashing Data In-Process
Mashing data in-process involves applying data integration techniques in the same process as the mashup page. This is typically accomplished with scripting code such as JavaScript and JScript. However, proprietary component technologies such as Java applets and ActionScript can be used.
During the process of mashing data in this model, a request is made to a service and data is returned in the service response. The data is then parsed, processed, and applied to UI artifacts in the page. DOM manipulation is typically used to apply the processed data.
Mashing XML Data In-Process
All standard web browsers expose an XML-parser object to JavaScript that can be used to load and parse XML data. Each parser reads XML data from a string; therefore, a string response returned from a service call can be passed to the XML parser and processed as needed.
In Listing 1.6, an XML parser is created and used to parse the XML document string defined previously in Listing 1.3. As each contact item is encountered, a new paragraph element is created using DOM manipulation, and the element is added to the web page.
Listing 1.6. Parsing XML Using JavaScript
<script> function parseXMLData(xmlString) { var xmlDoc; if (document.implementation.createDocument) { // Create the Mozilla DOM parser var domParser = new DOMParser(); // Create the XML document object xmlDoc = domParser.parseFromString(xmlString, "text/xml"); } else if (window.ActiveXObject) { // Create the Microsoft DOM parser xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = "false"; // Create the XML document object xmlDoc.loadXML(xmlString); } // get root node var contactsNode = xmlDoc.getElementsByTagName('contacts')[0]; // traverse the tree for (var i = 0; i < contactsNode.childNodes.length; i++) { var contactNode = contactsNode.childNodes.item(i); for (j = 0; j < contactNode.childNodes.length; j++) { var itemNode = contactNode.childNodes.item(j); if (itemNode.childNodes.length > 0) { var itemTextNode = itemNode.childNodes.item(0); var paraEl = document.createElement("p"); var textEl = document.createTextNode(itemNode.nodeName + ":" + itemTextNode.data); paraEl.appendChild(textEl); var bodyEl = document.getElementsByTagName("body").item(0); bodyEl.appendChild(paraEl); } } } } </script>
In the preceding listing a DOM parser is instantiated and is accessed to get the root node. Each node is then traversed via its child nodes until the desired text data node is found. Note that there is a different parser used for Microsoft Internet Explorer and Mozilla.
Mashing JSON Data In-Process
Since JSON is pure JavaScript, a string containing JSON data can simply be evaluated to create a JavaScript object. Then the JavaScript object can be accessed using normal JavaScript. For example, suppose that you are working with a string containing the JSON data shown previously in Listing 1.4. You can pass that string to the JavaScript eval function as follows:
var jsonObj = eval("(" + jsonString + ")");
This creates a JavaScript object on which we can operate using standard JavaScript techniques. For example, you can access the name field for the first contact using the following snippet:
jsonObj.contacts[0].name
Typically, you know the structure of the data beforehand. However, you might not know the length of array data within the structure. In that case, the JSON object must be traverse and array data parsed dynamically.
In Listing 1.7, a string containing JSON data, as defined previously in Listing 1.4, is evaluated and parsed. As each array element is encountered, a new paragraph element is created using DOM manipulation and the element is added to the web page:
Listing 1.7. Processing JSON Using JavaScript
function parseJSONData(jsonString) { var jsonObj = eval("(" + jsonString + ")"); for (var x in jsonObj) { // ignore properties inherited from object if (jsonObj.hasOwnProperty(x)) { if (jsonObj[x] instanceof Array) { // handle arrays for (var i = 0; i < jsonObj[x].length; i++) { var bodyEl = document.getElementsByTagName("body").item(0); // create name element var paraEl = document.createElement("p"); var textEl = document.createTextNode("Name: " + jsonObj[x][i].name); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); // create address 1 element paraEl = document.createElement("p"); textEl = document.createTextNode("Address 1: " + jsonObj[x][i].address1); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); // create address 2 element paraEl = document.createElement("p"); textEl = document.createTextNode("Address 2: " + jsonObj[x][i].address2); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); // create city element paraEl = document.createElement("p"); textEl = document.createTextNode("City: " + jsonObj[x][i].city); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); // create state element paraEl = document.createElement("p"); textEl = document.createTextNode("State: " + jsonObj[x][i].state); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); // create zip element paraEl = document.createElement("p"); textEl = document.createTextNode("Zip: " + jsonObj[x][i].zip); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); // create country element paraEl = document.createElement("p"); textEl = document.createTextNode("Country: " + jsonObj[x][i].country); paraEl.appendChild(textEl); bodyEl.appendChild(paraEl); } } } } }
With the ability to parse data returned from a service and to manipulate elements of the HTML DOM with the parsed data, you can dynamically create and modify UI artifacts to fit the needs of your mashup.
Mashing Data Out-of-Process
Mashing data out-of process involves applying data integration techniques in a separate process, typically on a remote host/server. In this mashup model, a remote software module receives requests from a client and takes the necessary steps to gather and transform the data needed to formulate a response.
Technologies and techniques in this approach overlap with enterprise data integration technologies and techniques, the scope of which is beyond this discussion. However, the following presents a high-level view of some of the more common approaches to enterprise data transformation and integration currently in use:
- Brute-force data conversion—This technique involves converting one data format to another using proprietary conversion tools or a custom byte-for-byte conversion program. Proprietary applications often offer an extension framework allowing third parties to build components or plug-ins that will convert one data format to another.
- Data mapping—Data mapping involves the creation and application of a map of data elements between two disparate data models—source and destination. The map is used by conversion programs to determine how an element from the source dataset applies to the destination dataset. Extensible Stylesheet Language Transformations (XSLT) is often used in this approach to convert XML data from one form to another.
- Semantic mapping—This approach uses a metadata registry containing synonyms for data elements that can be queried by conversion tools that use the synonyms as a guide for converting one data element to another.