Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Creating Generic XSLT Transforms-2 : Page 2


advertisement
Wrapping XSLT in Procedural Clothes
An XML Data Island is a Microsoft-specific way to include XML content within HTML pages in Internet Explorer. A data island has an <xml> tag with optional id and src attributes. While you can use data islands to provide local XML for data population operations, you can also use these islands to store your XSLT code. For example, you can create a data island consisting of the XML code in Listing 1 as follows:

<xml id="records">&#160; <records>&#160; <record id="101">&#160; <firstname>Kurt</firstname>&#160; <lastname>Cagle</lastname>&#160; </record> <!-- more records --> </records> </xml>

Similarly, you can store the XSLT as:

<xml id="_ShowRecords"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:param name="sortKey" select="'firstname'"/> <xsl:param name="sortOrder" select="'ascending'"/> <!-- more of the same --> </xsl:stylesheet> </xml>

You can then retrieve an XML DOM version of the data island with the XMLDocument property of the <xml> element. For example, to retrieve the XSL document as a DOM element using JavaScript, you would write:



var xslDoc= _ShowRecords.XMLDocument;

I added the underscore to the ID to indicate that this is a data island function as opposed to a simple transform.

XML documents created in this way are for the most part indistinguishable from xml documents loaded from a file, though with inline data islands you can't update the island's XML contents back to the island itself (usually not a major limitation). You can create a data island as inline code as shown above. In addition, you can reference XML (and XSL) files on the server through the src attribute. For example, if the transformation shown in Listing 4 is available on the server as the relative URL ShowRecords.xsl, then you can use the src attribute to create a reference to it from an empty data island:

<xml id="_ShowRecords" src="ShowRecords.xsl"/>

After you have the XML and XSLT documents in data islands, you can pass the XML to the stylesheet using some basic JavaScript. However, rather than writing a function that calls the stylesheet internally, you can pass the stylesheet itself as an argument to a generalized function, as well as passing additional parameters. I did this by creating a generic call() function in JavaScript (see Listing 5):

function call(xslIsland,xmlIsland){ var xslDoc = new ActiveXObject ("MSXML2.FreeThreadedDOMDocument"); var rsltDoc = new ActiveXObject ("MSXML2.FreeThreadedDOMDocument"); var xslTemplate = new ActiveXObject ("MSXML2.XSLTemplate"); xslDoc.load(xslIsland.XMLDocument); xslTemplate.stylesheet=xslDoc; var xslProc=xslTemplate.createProcessor(); xslProc.input=xmlIsland.XMLDocument; xslProc.output=rsltDoc; if (arguments.length > 2 && arguments.length % 2 == 0){ for (var i = 0; i < Math.floor ((arguments.length) / 2) - 1; i++) { paramName=arguments[2*i+2]; paramValue=arguments[2*i+3]; xslProc.addParameter (paramName,paramValue); } } xslProc.transform(); return rsltDoc; }

The call() function takes two primary arguments -- an XML data island reference and an XSL Data Island reference. While I could have passed both XML and XSL as DOMs, passing them as data island references de-emphasizes their roles as files and instead makes the function act more like a method. The following example shows how to invoke the call() function to display the records by first name in ascending order:

call(_ShowRecords,records,"sortKey","firstname", "sortOrder","ascending");

This technique encapsulates the XSL processing within a transparent process, with a very straightforward call syntax. Note, however, that a few parameters snuck into the call() function invocation. The function takes advantage of a JavaScript capability that VBScript doesn't support—the ability to create virtual parameters. The first two parameters specify the data on which the method works. Each succeeding pair of parameters contains a name and value that the call() function will in turn pass to the XSLT function as parameters. Thus, the first parameter is named "sortKey" with a value of "firstname", the second parameter is named "sortOrder" with a value of "ascending". This was specifically done with the arguments JavaScript collection:

if (arguments.length > 2 && arguments.length % 2 == 0){ for (var i=0; i < Math.floor((arguments.length)/2)-1; i++){ paramName=arguments[2*i+2]; paramValue=arguments[2*i+3]; xslProc.addParameter(paramName,paramValue); } }

The routine iterates over all arguments after the first two, retrieves the parameter name and parameter value (the parameters must be in that order), and then uses the XSL Processor object (part of the MSXML3 and MSXML4 library) to set the specified XSLT parameter name to the specified value.

By doing this you can make the call() function completely generic -- regardless of the data, the transformation, or the parameters that are involved in the transformation. It also means that you can define a number of XSLT "methods" in your page, then invoke them through the call() function. To simplify things somewhat for this case, I also wrapped this call() function for the particular case in another function, showRecords():

function showRecords(sortKey,sortOrder){ var resultDoc = call(_ShowRecords,records,"sortKey", sortKey,"sortOrder",sortOrder); window.container.innerHTML=resultDoc.xml; }

The showRecords() function uses the call() function internally to retrieve an XML DOM object that's placed in the variable resultDoc. The showRecords() function obtains the resulting XML string using the resultDoc.xml property and places the contents in the <div> element with the id "container," where it displays as HTML.

Download the code for the entire encapsulated.htm file. The user interface lets you select different views of the data table.

Into the Production World
While the example used in this article is fairly simple, a full web site can make use of the same techniques to define a general API for calling XSLT methods. For example, you can create XSLT methods to generate dynamic menus based upon XML resource files, form display based on XML record objects, article formatters based upon XML raw source and XSLT display engines, and so forth. Additionally, you can retrieve query string arguments and use them as parameters into more sophisticated methods that maintain state--an issue that also comes into play with clients because clients, unlike servers, generally are well optimized for keeping state information intact.

I'll explore this topic in more detail in future articles, where I hope to provide both client and server method call architectures (also known as web services, though only the most general sense). The combination of intelligent clients and intelligent servers using XSLT to shape the XML passing between them effectively changes the dynamic of web programming, making it both more flexible and easier to develop, not always an achievable goal.



Kurt Cagle is the author or co-author of twelve books and several dozen articles on web technologies, XML and web services. He is the president of Cagle Communications (Olympia, WA), which specializes in the production of training materials for XML and Web Services education. He can be reached at kurt@kurtcagle.net.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date