Wednesday, May 25, 2005

Dynamic control generation using XSLT

In a recent project, we needed to render .net controls dynamically. Instead of using ascx controls, we used XSLT to transform static Xml data into dynamic presentation layers; a viable approach to providing multiple look and feels for the site. Here's a quick walkthrough of how it works.

Dynamically loading the HTML is simple, using the built-in ParseControl method of the System.Web.UI.Page class.

Control c = Page.ParseControl( "<b> Literal Text </b>");

The same logic can be applied to parsing the output of an Xslt transformation.

string transformOutput = xslTransformer.Transform();
Control c = Page.ParseControl(transformOutput);

If you want to add server-side controls into the transformation, there are a few gotchas:

  1. XSLT parser needs namespace definitions for .net and custom tag prefixes.
  2. Namespaces appear as attributes in the formatted output, which will need to be stripped out before adding to the Page.Controls collection.

If you're adding asp.net controls or custom controls into your XSLT file, you'll need to declare the namespace at the top of the xslt header, otherwise the XML Parser will complain:

xmlns:asp="http://schemas.microsoft.com/AspNet/WebControls"

Incidentally, if you're using Visual Studio 2003, adding this namespace declaration will give you Intellisense for your asp.net controls in your XSLT file.

With all the proper namespaces defined, you'll bypass any nasty Xslt Parser errors, however, these namespaces will now appear scattered throughout your transformed output as attributes. If you leave these values in and try to parse the output into a control, the .net runtime will try to resolve the namespaces as attributes of the controls and will generate runtime errors.

Fortunately, a quick regular expression can strip all these namespaces out of the transformed output:

string transformedOutput = transformedOutput.Replace("xmlns:\w+=\"[^"]+\"", "");

With the namespaces stripped out of the transformed output, you should be able to parse the string into a control.

using System.Xml;
using System.Xml.Xsl;
using System.Web;

XslTransform transform = new XslTransform();
transform.resolver = new System.Uri("http://localhost"); 
string xslFilePath = Server.MapPath("/controls.xslt");
transform.Load( xslFilePath );

string xmlFilePath = Server.MapPath("/data.xml");
string transformedOutput = transform.Transform( xmlFilePath );
transformedOutput = transformedOutput.Replace("xmlns:\w+=\"[^"]+\"", "");

Control c = Page.ParseControl( transformedOutput ); 
Page.Controls.Add( c );

Cheers

submit to reddit

1 comments:

nettellect said...

if possible can u share the xslt so that it could be helpful to others.