Introducing Code Generation - Generating a Simple Class via XSLT Templates
(Page 13 of 13 )
Now compare these approaches with code generation via XSLT. Similar to the brute-force approach, the XSLT approach opens the XML metadata file. Instead of passing the XML metadata file to a specific class method to generate the code, the XML metadata directly drives code generation through an XSLT template:
Private Shared Sub GenerateClassViaXSLT(ByVal outputDir As String) ' Open Metadata file Dim xmlMetaData As New Xml.XmlDocument xmlMetaData.Load(IO.Path.Combine(xmlDir, "Metadata.xml"))
' Generate Hello World via XSLT Template GenerateViaXSLT(IO.Path.Combine(xsltDir, "Class.xslt"), xmlMetaData, _ IO.Path.Combine(outputDir, "ClassCustomersViaXSLT.vb"), _ New XSLTParam("TableName", "Customers")) GenerateViaXSLT(IO.Path.Combine(xsltDir, "Class.xslt"), xmlMetaData, _ IO.Path.Combine(outputDir, "ClassOrdersViaXSLT.vb"), _ New XSLTParam("TableName", "Orders")) End Sub
The XSLT template named Class.xslt holds the pattern definition, and its name is passed as the first argument to the GenerateViaXSLT method. The XMLDocument containing the metadata is the second argument to the generic transformation routine. The third argument is the output file path. The final argument is an XSLT parameter containing the name of the table for the created class.
Like all XSLT stylesheets, the stylesheet starts with some standard XSLT goo:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8" indent="yes"/> <xsl:preserve-space elements="*" />
The TableName parameter allows the creation of the target class for a subset of the XML metadata:
<xsl:param name="TableName"/>
The XSLT instructions that create output are contained in two XSLT templates. The first template matches the root element. Within this template, a second matching template is processed only for tables whose name matches the TableName parameter (there’s only one). Don’t worry if this syntax seems strange because Chapter 3 has XSLT examples, and you can read Appendix A when you want to learn more about XSLT details. At this point, it’s only important that you have a general idea that this template calls the following template for only the table with which you’re working:
<xsl:template match="/DataSet">
<xsl:apply-templates select="Table[@Name=$TableName]"/> </xsl:template>
This second template contains the code to output, including the normal option and imports statements. The class declaration uses the first of several XSLT constructs that are important to code generation. The xsl:value-of construct provides a mechanism for token replacement. It outputs data from the XML input, XSLT variables, template parameters, and XPath functions. In this case, the inserted value is the contents of the TableName parameter. In XSLT, you prefix variables with the dollar sign ($):
<xsl:template match="Table"> Option Strict On Option Explicit On
Imports System
'! Class Summary: Simple class example
Public Class <xsl:value-of select="$TableName"/>
Creating the field variables uses another important XSLT construct. The xsl:for-each is one of two mechanisms for looping through code. The other is the xsl:apply-templates directive. Each of these directives selects a set of nodes and sets the context to each active node while looping through the node-set. (Appendix A clarifies when to use each construct.) XSLT is highly reliant on the concept of context. The simplest way to think of context is to imagine you have a printed copy of your XML input document and point your finger at a particular element. Each time the xsl:for-each loop is processed, the context moves to the next node in the selected list of nodes—in this case, child elements named Column:
#Region "Class level declarations" <xsl:for-each select="Column">
Private m_<xsl:value-of select="@Name"/> As <xsl:value-of select="@Type"/> </xsl:for-each> #End Region
Code in the xsl:for-each loop outputs the field variable for each column. The xsl:value-of directive outputs the Name and Type attributes from the current node in the XML input document at the appropriate locations. You prefix attributes with the at (@) sign. In the context of the xsl:for-each loop, the Name attribute is the current column’s name, and the Type attribute is the column’s type.
The second xsl:for-each loop creates the output code for the property. Here the xsl:value-of directive again accesses the attributes of the column. The XSLT logic is similar to the previous loop, but the extra text makes the output look quite different:
#Region "Public Methods and Properties" <xsl:for-each select="Column"> Public Property <xsl:value-of select="@Name"/>() As <xsl:value-of select="@Type"/> Get
Return m_<xsl:value-of select="@Name"/> End Get Set(ByVal Value As <xsl:value-of select="@Type"/>)
m_<xsl:value-of select="@Name"/> = Value End Set End Property </xsl:for-each>
#End Region
End Class </xsl:template>
</xsl:stylesheet>
If you compare this with the earlier XSLT template, you’ll see that the template for a much longer and more complex target file is only a few lines longer than the “Hello World” example. Ignoring the standard XSLT goo copied from the template, the CodeDOM and brute-force examples that create the same file are significantly longer. Each line is also significantly simpler, and the distinct languages (XSLT and VB .NET) differentiate the varying elements and template logic from target output code. The XSLT directives are also visually distinct from the output code.
If you’re new to XSLT, the template may look a little strange. It may even be scary or intimidating because XSLT encourages you to think in a different way. But, by the time you’re comfortable with XSLT, you’ll be very comfortable reading the code in these templates, and you’ll see that this different way of thinking can help you filter the target output from the template structure, each of which will be important to you at different times.
NOTE You can find all the code in this book in the Downloads section of the Apress Web site (http://www.apress.com).
Summary .NET gives you three viable options for application code generation depending on what you’re trying to accomplish:
- Brute-force code generation (spitting out code to file streams)
- CodeDOM generation
- XSLT code generation
For all three mechanisms, the power of code generation is that you can apply the pattern to any XML metadata that matches the anticipated format. Once created, you can use any of these patterns repeatedly to create the target code for any metadata in the expected format.
Just spitting out code might help your project, but it won’t give you the full benefit of code generation. For that, you need to make a conscious process. The five distinct steps of application code generation are as follows:
- Architecting and designing (figuring out what to build)
- Extracting metadata (organizing the application-specific input)
- Creating and running code generation (creating reusable templates and generating code)
- Handcrafting code (customizing your application and building components)
- Implementing and testing (delivering your application sooner)
The five principles of code generation parallel these five steps. These are the non-negotiables:
- You’re in control.
- Metadata extraction is a separate step.
- Regeneration is a precise repeatable one-click process.
- Code generation embraces handcrafted code and protects it across regeneration cycles.
- Code-generated applications meet or exceed traditional applications in quality, performance, and maintainability.
Additional Reading To find more information about the topics covered, try these resources:
- For more information about the CodeDOM, go to www.msdn.microsoft.com and search for .NET CodeDOM.
- A classic book on formally described design patterns is Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley, 1995).
- You can also refer to Professional Design Patterns in VB .NET: Building Adaptable Applications by Tom Fischer, Chaur Wu, and Pete Stromquist (Apress, 2003).
- Finally, a helpful book is .NET Patterns: Architecture, Design, and Process by Christian Thilmany (Addison-Wesley, 2003).
This chapter is from Code Generation in Microsoft .NET by Kathleen Dollard (Apress, 2004, ISBN: 1590591372). Check it out at your favorite bookstore today.
Buy this book now. |
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |