You may be wondering, with all the hype over XML, what can XML do for me today?

You see the power of XML but may be having a hard time figuring out where it belongs in your application development strategy. In this article browser based applications will be discussed from the perspective of using XML as the data transport mechanism.

Building or converting your HTML application to use XML data ensures your application's ability to deliver data to any front-end in the future. The reach of your application can now extend to Fat Clients, Thin Clients and Mobile clients, in addition to supporting the standard browser-based clients. If your application has any business-to-business functionality, converting to XML will provide an open interoperability standard for your business partners. Client side XML data also dramatically increases the performance and scalability of your application servers as more processing is pushed to client computers.

This article assumes you are targeting IE 5.0 and greater as your browser platform. All source code contained in this article can be downloaded from my web site: http://home.earthlink.net/~jnewell/codemag/ie5databinding.zip. Download this zip file and follow the read.me instructions.

What's wrong with HTML?

Many web based applications could be considered “HTML only clients”. The only means ever used to run these applications is the standard HTML browser. Data delivered to the browser is directly embedded into the HTML response, typically as form variable values. The response does not differentiate between client types and always contains HTML markup.

Windows DNA Web applications that have an N-Tier structure connect across physical tiers by using data structures such as XML and HTTP connections to share data over the wire. Most HTML browser based applications tend tobreak the DNA model and combine the data access logic and the HTML creation in one operation executing at the server. Most applications that use Microsoft's Active Server Pages (ASP) combine these two steps in ASP script code, possibly aided calls to COM components on the server side. One could argue that server driven ASP pages are not true DNA applications because the client is essentially a static non-participant in the n-Tier model.

The biggest problem with the static or combination approach is poor interoperability. Only browser clients are supported. Support for a new type of client (a Fat Client application for example) involves major rewrites of data access logic. Another problem is server resource utilization. The server has to gather all the data for a request and then construct HTML on the fly even though the HTML form is essentially static. Binding the data to HTML form fields on the server side forces the on-the-fly approach to HTML creation that limits the application to HTML only clients. Using XML as the data transport mechanism and binding the data to the HTML in the browser overcomes these problems and leaves you with a more manageable application that scales better to a more diversified client universe.

Separating the display from the content with XML

The first step of this process involves separating the data portion of a request from the HTML portion. The easiest way to this is by including XML fragments in the server response. Some developers refer to this inline XML as Data Islands. After the browser receives the response it will then perform a client side operation to bind XML Data Islands to the HTML form fields. Lets look at a quick example of what the response from the server may look like (dept.asp):

<html>
  <head>
    <XML ID="DEPT_RS">
      <DEPT_RS>
        <DEPT PK="0000000010" TIMESTAMP="000000000000100D">
          <NAME>Accounts Payable</NAME>
          <DEPCODE>1238</DEPCODE>
        </DEPT>
      </DEPT_RS>
    </XML>
    
    <title>Data Binding Sample</title>
    <script language="JavaScript" src="databinding.js"></script>
  </head>

  <body onLoad="binddata();" >

    <form METHOD="POST" ACTION="DEPARTMENT.ASP&MODE=POSTDATA">
      Department Name <input TYPE="text" NAME="txtName" XMLTABLE="DEPT" XMLFIELD="NAME" /><br />
      Department Code <input TYPE="text" NAME="txtDepCode" XMLTABLE="DEPT" XMLFIELD="DEPCODE" /><br />
      <input TYPE="SUBMIT" Value="SUBMIT"/>
    </form>

  </body>
</html>

This looks like a standard HTML response. The HTML form consists of a simple form with two input tags and a submit button. An XML data island that contains the actual data for the request has been included inside the <HEAD> tag:

<XML ID="DEPT_RS">
    <DEPT_RS>
        <DEPT PK="0000000010" TIMESTAMP="000000000000100D">
            <NAME>Accounts Payable</NAME>
            <DEPCODE>1238</DEPCODE>
        </DEPT>
    </DEPT_RS>
</XML>

XML Databinding at work

Let's look at data binding in action, this involves copying the XML data island to the corresponding bound HTML element. This example shows a single record binding to HTML form fields. You could just as easily bind to multiple records using any HTML element. There is a very important distinction to make ? the data binding is happening at the client as opposed to the server. Data binding at the client also forces good N-Tier separation of roles and responsibilities by its basic design.

Data is bound to the HTML dynamically using HTML tag attributes on input fields and some script code. The <input> tag attributes XMLTABLE and XMLFIELD allow each HTML form field to specify a data binding back into the XML data island. These attributes are not standard HTML tags, but in IE 5.0 HTML permits ad hoc tag attributes. The tag attributes are accessed as properties in the data binding script code. This is very similar to data binding in other languages where properties are used to define the namespaces in which data binding operations operate.

<input TYPE="text" NAME="txtName" XMLTABLE="DEPT" XMLFIELD="NAME" />

The XMLTABLE attribute specifies the XML data island ID. The XMLFIELD attribute specifies the column level binding to the form element. The actual binding occurs on the client when the browser loads the document by using the <body> tag's onload event:

<body onLoad="binddata();">

I have isolated the data for this request in the form of an XML data island in this example, but in theory you could also dynamically download the data from the server using the Microsoft XMLHTTP component included with Internet Explorer 5.0. From the perspective of string operations performed at the server everything in this request is static except the XML data Islands in the <head> tag.

In fulfilling a request the server simply merges The XML data island for a request with the static HTML in a single string transformation. This is far more efficient than forcing the server to iterate through complex string operations and building HTML “on-the-fly”. It also allows HTML authors without any knowledge of server side coding, to create and maintain all HTML. Likewise, server side developers need not have any knowledge of HTML. On larger projects this provides for a scalability of skill sets and human resources.

I have also specified how each HTML form element binds to the values in the XML data islands using customized form element attributes. We now need to look at how the data is bound, or copied, from the XML data island to the bound form element. This is accomplished with a custom JavaScript function called binddata(). The actual data binding code is encapsulated in a library for efficiency. The library is included in the response via the <script> tag:

<script language="JavaScript" src="databinding.js"></SCRIPT>

Here is the actual source code for the binddata() function found in the generic library databinding.js:

// FILE databinding.js - DATA binding example
function binddata() {
    var loForm = DOCUMENT.FORMS[0];
    for (var lnElement = 0; lnElement < loForm.LENGTH; lnElement++) {
        var loField = loForm.elements[lnElement];
        if ((loField.XMLTABLE == NULL) || (loField.XMLFIELD == NULL)) continue;
        var loIsland = DOCUMENT.ALL(loField.XMLTABLE+"_RS");
        loIsland = loIsland.XMLDocument.documentElement;
        var loRow = loIsland.selectNodes("//"+loField.XMLTABLE).ITEM(0));
        var loXMLField = loRow.selectSingleNode(loField.XMLFIELD);
        loField.VALUE = loXMLField.TEXT;
    }
    return true;
}

Let's review how this binding code works. A loop is setup that iterates through all form elements on the form:

var loForm = document.forms[0];
for (var lnElement = 0; lnElement < loForm.length; lnElement++)

Next, the data binding attributes are checked. If a particular form element does not bind to data it will not include the XMLTABLE or XMLFIELD attributes. The loop will skip these “non-binding” form elements using the following code:

if ((loField.XMLTABLE == null) || (loField.XMLFIELD == null)) continue;

Now the binding code will isolate the XML data island by ID. By convention the island ID is the same as the table name with a _RS suffix. (_RS is short for record set) :

var loIsland = document.all(loField.XMLTABLE+"_RS");

The isolated XML data island is now typecast into an XML document:

loIsland = loIsland.XMLDocument.documentElement;

The first record is then isolated in the XML data island. Effectively we are selecting row 0 from the XML data island. If we were binding to a control that supported multiple records we would have to loop through each record and bind the data for each row in the loop:

vaxr loRow = loIsland.selectNodes("//"+loField.XMLTABLE).item(0));

Now that the data source and the correct row are selected, the column data can be extracted:

var loXMLField = loRow.selectSingleNode(loField.XMLFIELD);

Finally the assignment from XML Data Island value to HTML form element occurs:

loField.value = loXMLField.text;

With relatively little coding we have now created a generic way to bind data to HTML form elements when a request loads into the browser. You can take both the JavaScript and HTML code fragments above and try them on your web server if you like, they are working examples. (IE 5.0 is required)

The next step is to keep the XML data islands synchronized with the form fields they are bound to. We will need a new, custom JavaScript function added to our data binding library (databinding.js). The SyncronizeData() function will ensure that changes to form elements are updated back into the XML data islands. We will hook this function into each form element using the “onChange” event:

<input type="text" name="txtName" XMLTABLE="DEPT"  XMLFIELD="NAME" onChange="syncdata();" />

Here is the source for the new function:

function syncdata()
{
    var loField = window.event.srcElement;
    var loIsland = document.all(loField.XMLTABLE+"_RS");
    loIsland = loIsland.XMLDocument.documentElement;
    var loRow = loIsland.selectNodes("//"+loField.XMLTABLE).item(0);
    var loXMLField = loRow.selectSingleNode(loField.XMLFIELD);
    loXMLField.text = loField.value;
}

syncdata() is another simple function. The first thing the function does is to get a reference to the field that has called syncdata:

var loField = window.event.srcElement;

Next, a reference to the XML data island field that the form element is bound to is created. This portion of the code is identical to that found in the binddata() function:

var loIsland = document.all(loField.XMLTABLE+"_RS");
loIsland = loIsland.XMLDocument.documentElement;
var loRow = loIsland.selectNodes("//"+loField.XMLTABLE).item(0);
var loXMLField = loRow.selectSingleNode(loField.XMLFIELD);

Finally, the value of the form element is updated back into the XML data island:

loXMLField.text = loField.value;

Posting XML Back to the server

We now have an HTML form that loads its data from XML data islands and saves changes to the form elements back into the data islands. The final step is posting the XML back to the server. This is very easy to accomplish with some simple code. First the client side JavaScript that posts the data:

function postxml(lcIsland)  {
    try {
        var loSave = new ActiveXObject("Microsoft.XMLHTTP");
        loSave.OPEN("post", "datapost.asp", false);
        loSave.SEND(DOCUMENT.ALL(lcIsland+"_RS").XMLDocument);
        alert("Data has been posted to server: \n" +
        loSave.responseText);
    }
    catch(anyError) {
        alert("Error","Unable to process request to server");
    }
    return;
}

Posting data in this manner does not change the document or navigate to a new URL as do form submissions. This allows you to validate a save or perform other logic before navigating or refreshing the HTML document.

Lets review the posting code. First, a new instance of Internet Explorer's built in XMLHTTP COM object is created. This will be used to post the data via HTTP back to the server.

var oRequest = new ActiveXObject("Microsoft.XMLHTTP")

Next, XMLHTTP is to setup to send the XML Islands back to the server:

loSave.open("post", "datapost.asp", false);
loSave.send(document.all(lcIsland+"_RS").XMLDocument);

Finally the response from the server is displayed to the user.

alert("Data has been posted to server: \n" + loSave.responseText);

Here is the .ASP server side script code that accepts the post:

<%
    response.ContentType = "text/xml"
    Set oXML = Server.CreateObject("Microsoft.XMLDOM")
    oXML.async = false
    oXML.Load(request)
    response.write(oXML.xml)
%>

Back at the server, .ASP script code will be used to load the XML into a parser. Depending on the development language and data access technology you select, what you will actually do with the XML after its loaded into a parser instance on the server will vary. The server can now look at the XML posted by parsing the XML document and updating the database as needed.

Conclusion

That's all there's to it! We now have an HTML client that uses XML based representation of data. You can extend this example by downloading data dynamically from the server using the XMLHTTP component and using the retrieved XML in the binddata function instead of the static XML embedded in the ASP/HTM page to provide a true interactive client.

No more server side parsing of data into fields and no more server roundtrips to refresh and update data on the client! More importantly we have unbound the GUI from the data portion of the request and increased our applications scalability and reach. In a future article we will expand these concepts and look at how to prepare the data to be sent to the client from the application server side.