Presenting Data with the XML DSO

In the early '90s, one very popular feature of the so-called rapid application development (RAD) tools was the data-bound control. These "data-aware" controls were popular because they possessed internal logic to retrieve, display, modify, and write database records. Thus, it was easy for the PowerBuilder developer, or Visual Basic or Borland Delphi programmer to create a table that paged through and presented database records.

Many of these early controls have long since been standardized into what Microsoft calls Data Source Objects, or DSOs. Generally speaking, DSOs are ActiveX controls that let you establish a connection between the control and a data source. Once the connection is established, the DSO lets you populate forms, fields, tables, edit controls, and similar objects with data. In most cases, DSOs have the ability to update themselves dynamically. Therefore, users have the experience of a live data connection.

As part of its increasing support for XML, Microsoft introduced the XML DSO in Internet Explorer 4. The XML DSO lets you bind markup from an XML document with HTML presentation elements. The markup can come from an external data source, or it can be contained in an XML data island. The cool thing about these DSOs is that since they maintain live connections to the data source, your Web pages can update themselves as new XML data streams arrive.

This month, I'll examine the XML DSO and show how you can quickly grab XML text and present it in a browser. I'll assume you know how to mark up XML documents and that you're familiar with XML data islands (see " Online" for reference materials). To use the XML DSO, your clients must be running IE4 or later. For practical applications, they should be running IE5.

Presenting XML from a Data Island

The simplest method for presenting XML is when it is contained in a data island. To see how this might work, consider an employee database, which is being maintained by the human resources department. Let's assume that HR is conducting a survey that compares the salaries of employees at similar levels of responsibilities in different departments. This may help identify departments that are lagging in compensation or help establish a salary range for a newly created position.

To show how you would present this kind of data, Listing One presents an HTML document containing an XML data island. The data island has been assigned the name employeeDB. In this particular example, a human resources person is comparing the salaries for directors within the company.

To display the elements, I use a <TABLE> element. To link my table to the XML data, Listing One assigns the name of our data island to the datasrc attribute. This is the same name that was defined in the ID attribute for the <XML> element. In making this assignment, you must precede the name of the data island with the pound sign (#). Next, I create a <DIV> element within each cell of the table. Recall that the <DIV> element lets you assign an arbitrary value to an attribute. So, when the XML DSO sees the datafld attribute, the DSO checks its value, then populates the cell with its associated value.

The cool part is that the DSO formats additional rows automatically. In other words, we don't have to know how many rows to create in the HTML table. Much like XSL's for-each construct, the DSO iterates through each <employee> instance, automatically creates the additional rows, and populates each cell. That saves you from having to script such a feature.

I should also mention that you can display all fields from a given record using the $Text identifier. The fields returned in $Text are concatenated together. So, you could rewrite Listing One to dump all of the database fields into a table using the code in Listing Two.

Linking to External Sources

As you can see from the previous example, linking the table to an XML data island is a simple matter of referencing the data island's ID. The process is a bit more complicated when you want to link to an external XML data source. The first step is to insert an instance of the XML DSO into your Web page. One way to do this is by using the <OBJECT> element, as in Example 1.

The classid attribute contains a namespace that explicitly identifies the XML DSO. The ID attribute acts as an alias, letting us refer to this object by a much shorter name. The next step is to bind the DSO to your XML. For instance, the JScript code in Example 2 loads our XML document and exposes its elements through the DOM API. I should mention that Microsoft has also extended the <OBJECT> element to accept inline XML, as shown in Listing Three.

Paging Through Data

With larger sets of data, you want to present data in pages and let the user page back and forth through screens. Normally, this would involve a lot of JavaScript to manage the table and retrieve the proper portions of the data set. Fortunately, the DSO handles all of this for you. All you have to do is set the DATAPAGESIZE attribute in the <TABLE> element, as in Example 3.

The XML DSO provides four methods to page through data sets: nextPage, previousPage, firstPage, and lastPage. To see how this works, consider Listing Four. After initializing the XML DSO and loading it with data, the <BODY> of this Web document sets up four buttons that let the user go to the first page of data, advance to the next page, page back, and go to the last page, respectively. Each button's ONCLICK property points to a method that navigates to the appropriate page. The methods are prefixed with the name myTable. This is the name given in the ID attribute of the subsequent <TABLE> element.

The <TABLE> element also sets DATAPAGESIZE so that 20 records will be shown in a page view at a time. In addition, the datasrc is set to employeeDB. Note that there's no pound sign (#) prefixing the data source name. That's because we're not using a data island, but are instead referring to the document employeeDB object created in the <SCRIPT> portion of the document. Now all that's left to do is fill the rows with data from employeeDB.xml.

Assigning Elements to Tables

In assigning elements and attributes to table cells, the XML DSO follows a specific procedure. In general, the XML DSO traverses the tree structure created when parsing your XML document, and assigns cells in "document order." Each subelement and attribute corresponds to a column in some rowset in the hierarchy, and the root or document element is never included in the table. In general, the element or attribute name is assigned to the name of the column. However, one exception is when the parent and child nodes have the same name. In this case, the subelement's column name is prefixed with an exclamation point (!).

In assigning values, each column is considered either as a simple column containing a scalar value (usually a string) or a rowset column containing subrowsets. Columns corresponding to attributes are always simple.

Columns corresponding to subelements are rowset columns if either the subelement has its own subelements and/or attributes, or the subelement's parent has more than one instance of the subelement as a child. Otherwise the column is simple. When there are multiple instances of a subelement (under different parents), its column is a rowset column if any of the instances imply a rowset column; its column is simple only if all instances imply a simple column.

The DSO in IE4

While the XML DSO was available in Internet Explorer 4.0, it has been necessarily modified to keep up with changing standards and subsequent support. The problem with change is that your code may break in certain versions of the browser. So, if you plan to support IE4, you'll want to set a flag, called JavaDSOCompatible, to true. Setting this flag makes the IE5 XML DSO compatible with the Java DSO supplied with IE4. You can set this flag either within an inline section of an XML data island, or when creating a new instance of the XML DSO. For instance, the <XML> element accepts the flag as an attribute, as in Example 4.

Of course, inline XML wasn't available in Internet Explorer 4.0. If you don't want to use inline XML, you can instead set the flag when using the <OBJECT> element to instantiate the XML DSO ActiveX control. The code in Example 5 does just that.

So far, none of the previous examples assumes the existence of a document type definition (DTD). When you introduce a DTD, the rules for converting elements and attributes into rows and columns change a bit. Each subelement and attribute named by the DTD corresponds to a column in some rowset in the hierarchy.

The name of the column is the same as the name of the subelement or attribute, unless the parent element has an attribute and a subelement with the same name, in which case a ! is added as a prefix to the subelement's column name.

Each column is either a simple column containing scalar values (usually strings) or a rowset column containing subrowsets. Columns corresponding to attributes are always simple. Columns corresponding to subelements are rowset columns if either the DTD allows the subelement to have its own subelements and/or attributes, or the DTD allows the subelement's parent to have more than one instance of the subelement as a child. Otherwise the column is simple. Finally, content corresponding to the content model ANY is not included in the rowset hierarchy.

Putting It Together

Listing Five takes an XML data stream that represents database records. The records are from a database of XML tools. Such a data stream could have been sent by the server in response to a database query. To test our example, the sample data stream contains three records. To save space, they've been abbreviated: Each of the three records is contained in a <product> element that contains information about a product as well as details about the company offering that product. The entire data stream is wrapped in a <productDB> element.

Also note that an XSL style sheet is referenced in the XML data stream. This style sheet would normally be used to transform the data stream to HTML. However, since we're using IE5, we can create an HTML table that automatically binds the XML data to the style sheet. This table will override any styles established by the style sheet.

Listing Six uses the <XML> element to create an XML data island. The src attribute specifies the URL for the database result set, which is loaded into the data island. The ID attribute lets us reference the data island through a script. By creating a data island, we automatically create a new data-source object and load it with the XML data stream, thus avoiding the <OBJECT> tag syntax.

More importantly, the XML DSO lets us map our data to a number of HTML elements including tables. All we need to do is map the table to the data source using the datasrc attribute. The value used in the attribute, initially created in the ID attribute of the data island, must be prefixed with the pound sign. After that, populating the table is a simple matter of specifying the record fieldnames.

Conclusion

When it comes to populating a table with fields from a database, you actually have three options: You can use a data-source object (either through a data island or by instantiating the DSO ActiveX control). Alternatively, you can create an XSL style sheet to format and present the data. Finally, you can load the XML document into a DOM object and access it through the DOM API. The difficulty of implementation increases with each option. Ultimately, the choice you make depends on the complexity of the data, how you need to process it, and the capabilities of your users. However, if you can guarantee your users are running Internet Explorer, using the XML DSO makes child's play out of database presentation.

(Get the source code for this article here.)


Michael is the author of Building Web Sites with XML from Prentice Hall. He provides XML training to large companies and publishes LifestylesSantaCruz.com. He can be reached at mfloyd@lifestylesSantaCruz.com.




Copyright © 2003 CMP Media LLC