HomeASP.NET Developing XSLT-based Applications in ASP....
Developing XSLT-based Applications in ASP.NET 2.0
This is the first article in a series focused on developing XSLT-oriented applications using ASP.NET 2.0. Even though the title includes ASP.NET 2.0, I use it only as a transformation engine. The entire focus will be on working with XSLT. You can use any transformation engine according to your requirements (such as Java or others).
The entire solution (source code) for this article is available as a free download in the form of a zip file. All the applications in this series have been developed using Microsoft Visual Studio 2005 Professional Edition on Microsoft Windows Server 2003 Standard Edition together with Microsoft SQL Server 2005 Developer Edition as the database. I didn’t really test any of the code in any of the other tools/IDEs/servers/editions/versions. If you have any problems, please feel free to post in the discussion area.
How to transform XML to XSLT using ASP.NET 2.0
Transforming XML to XSLT using ASP.NET 2.0 is quite easy. Working with the XML control (available in the toolbox) makes it easy to transform any XML document to the specified XSLT.
As it is a bit tedious to always author XML documents, I simply converted the output of a result set (or dataset) to an XML document by using the following method:
PrivateFunction getXMLContent(ByVal SQL AsString) As XmlDocument
Dim ds AsNew DataSet("SQLData")
Dim da AsNew SqlDataAdapter(SQL, "data source=laptop2k3sql2k5;initial catalog=AdventureWorks;user id=sa;password=eXpress2005")
da.Fill(ds, "Rows")
da.Dispose()
Dim sw AsNew System.IO.StringWriter
ds.WriteXml(sw)
ds.Dispose()
Dim docXML AsNew XmlDocument
docXML.LoadXml(sw.ToString())
sw.Close()
Return docXML
EndFunction
The above method accepts a SELECT query and returns XML in the form of an object of type “XmlDocument.” You may need to modify the above method to suit your production requirements.
Now, let us see how to transform the XML document to the specified XSLT. The following is the code used to achieve the same:
ProtectedSub Button1_Click(ByVal sender AsObject, ByVal e As System.EventArgs) Handles Button1.Click
Dim docXML As XmlDocument = getXMLContent("select EmployeeID, FirstName, JobTitle from HumanResources.vEmployee")
Me.txtXML.Text = docXML.InnerXml
Dim xp AsNew XPath.XPathDocument(New XmlTextReader(New IO.StringReader(docXML.InnerXml)))
To work with the above code, you need to drag and drop an XML control from the toolbox onto the web page. You may have to modify the name of the XSLT file according to your design or theme.
When the button is clicked (as given in previous section), it generates an XML document (from the database), which is similar to the following hierarchy:
<SQLData>
<Rows>
<EmployeeID>1</EmployeeID>
<FirstName>Guy</FirstName>
<JobTitle>Production Technician - WC60</JobTitle>
</Rows>
<Rows>
<EmployeeID>2</EmployeeID>
<FirstName>Kevin</FirstName>
<JobTitle>Marketing Assistant</JobTitle>
</Rows>
.
.
.
</SQLData>
The following is the first sample XSLT to test:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<b>
<xsl:value-ofselect="SQLData/Rows/FirstName"/>
</b>
</xsl:template>
</xsl:stylesheet>
When the XML document gets transformed based on the above XSLT, it displays the “FirstName” of the first employee in bold. The result of the above transformation would be similar to the following:
<b>
Guy
</b>
The first and the most important construct is the following:
<xsl:templatematch="/">
.
.
</xsl:template>
Any construct starting with “xsl:template” is called a “template.” The template is a blueprint for transformation. In the above case, it checks whether the current “context” is at “root” or not. If the “context” is at root, the template available within the construct is applied.
The following is the body of above template:
<b>
<xsl:value-ofselect="SQLData/Rows/FirstName"/>
</b>
The above transforms the first value (or text) available in “SQLData/Rows/FirstName” to display as bold.
The above XSL simply transforms only the text available in the “FirstName” tag (at any location in the document). All the rest would be directly displayed without any transformation.
If you wanted to handle the “FirstName” separately from root, you can rewrite the above XSLT as follows:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<xsl:apply-templates />
</xsl:template>
<xsl:templatematch="FirstName">
<b>
<xsl:value-ofselect="."/>
</b>
</xsl:template>
</xsl:stylesheet>
The above includes both root and “FirstName” templates. According to the above XSLT, when it finds “FirstName,” it goes to the template defined outside the root template.
If you forget to provide the following statement:
<xsl:apply-templates />
it would be a blank template and nothing would get displayed (or transformed).
In the previous section, we observed that we can include any number of templates according to our requirements. Now, let us consider how we would extract only the “FirstName” (without any other data) and transform it using the template. The following code handles this task:
That statement particularly says that it needs to apply a separate template (if available) if it finds “FirstName” at the path “SQLData/Rows.”
In the above case, it searches for “FirstName” only at the path “SQLData/Rows.” Let us consider defining and applying a template for “FirstName” available at any path. You may need to modify the above code to the following to achieve the same:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<xsl:apply-templatesselect="//FirstName" />
</xsl:template>
<xsl:templatematch="FirstName">
<b>
<xsl:value-ofselect="."/>
</b>
<br />
</xsl:template>
</xsl:stylesheet>
When you precede the path with “//” it reflects to “any path.”
Let us now consider working with more than one tag at a time (belonging to the same row or siblings). The following code sample achieves the same:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<xsl:apply-templatesselect="SQLData/Rows" />
</xsl:template>
<xsl:templatematch="SQLData/Rows">
<xsl:value-ofselect="EmployeeID"/>,
<b>
<xsl:value-ofselect="FirstName"/>,
</b>
<br />
</xsl:template>
</xsl:stylesheet>
From the above you can understand that I defined a new template for “SQLData/Rows.” Within that template, I am extracting “EmployeeID” and “FirstName” and transforming them according to our needs.
Let us now further extend the above XSLT to have sibling level and tag level templates as shown in the following:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<xsl:apply-templatesselect="SQLData/Rows" />
</xsl:template>
<xsl:templatematch="SQLData/Rows">
<xsl:value-ofselect="EmployeeID"/>,
<xsl:apply-templatesselect="FirstName" />
<br />
</xsl:template>
<xsl:templatematch="FirstName">
<b>
<xsl:value-ofselect="."/>,
</b>
</xsl:template>
</xsl:stylesheet>
As you can see, you can define and work with any number of templates at various levels according to your needs.
Since we are now a bit more familiar with templates, let us go for a practical example. I would like to display employee information in the form of an HTML table (by using only templates). The following code achieves the same:
In the root tag, I am simply emitting a TABLE tag. In the “Rows” template, I am emitting TR and TD tags. The TD tags will be filled with the values extracted using “xsl:value-of.”
Is there any possibility of achieving this without using templates at all? Yes. You can still do it. Go through the following example:
From the above you can understand that it displays all “FirstName” related information in bold. What if I want to display the “EmployeeID” along with the “FirstName?” In the above path, I didn’t specify “EmployeeID” at all and the template simply belongs to “FirstName.”
Now within the “FirstName” template, I would like to access the “EmployeeID.” It is the previous tag at the same level (or it is simply a preceding sibling). The following will help you understand how to access previous and next siblings:
The power of using XSLT solely depends on your grasp of XPath. I strongly suggest you to learn XPath before you learn XSLT. You can also find different utilities on this web site for learning XPath. Good luck.
I hope you enjoyed the article and any comments, suggestions, feedback, bugs, errors, enhancements etc. are highly appreciated at http://jagchat.spaces.live.com