Programmer to ProgrammerTM  
Wrox Press Ltd  
   
  Search ASPToday Living Book ASPToday Living Book
Index Full Text
 
ASPToday Home
 
 
Home HOME
Site Map SITE MAP
Index INDEX
Full-text search SEARCH
Forum FORUM
Feedback FEEDBACK
Advertise with us ADVERTISE
Subscribe SUBSCRIBE
Bullet LOG OFF
                         
      The ASPToday Article
March 14, 2002
      Previous article -
March 13, 2002
   
 
   
   
   
Creating XSLT – a Windows Forms XSLT Wizard, Part 2   Kevin Farnham  
by Kevin Farnham
 
CATEGORIES:  .NET Framework, XML/Data Transfer  
ARTICLE TYPE: Tutorial Reader Comments
   
    ABSTRACT  
 

XML is rapidly becoming the de facto standard for interconnectivity between diverse software applications, as well as for data exchange within applications. However, as XML is applied to increasingly complex systems, the structure of the XML becomes complex, making comprehension of the XML difficult if it is in its native format.



In this article, Kevin Farnham illustrates the development of an automated wizard that analyzes a generic XML data stream, characterizes its structure, and produces an extensible stylesheet language transformation (XSLT) to enable a software developer to conveniently view the XML contents. Part 1 of this article presented an XSLT Wizard for XML that represents structured data. Part 2 extends the Wizard for less structured XML that represents diverse documents that would not normally originate in a database or other structured data store.




   
                   
    Article Discussion   Rate this article   Related Links   Index Entries  
   
 
    ARTICLE

Introduction

Part 1 of this article developed a C# Windows Forms program that generates extensible stylesheet language (XSL) files and transforms XML that represents structured data. This is useful for XML that consists of elements representing a type of item or data object, each having an identical set of child elements representing the properties or characteristics of the parent data object. XML structured in this manner is conveniently presented in a table, which is what the wizard in Part 1 outputs for this type of structured data XML. The Part 1 program cannot process any other input XML.

Automating the creation of XSLs for highly structured data XML was relatively straightforward. However, devising an automated method for generating an XSL that can transform any input XML, with arbitrarily complex repeated patterns, or with no structure at all, is a much more difficult task. In this case, we must design an XSL transformation method based on the following assumptions:

Based on these assumptions, an entirely different XML analysis was developed to enable the XSLT wizard to generate XSL transformations for generic document XML. The document XML analysis utilizes two .NET XML classes ( XmlDocument and XmlNodeReader) that were not used in the structured data XML analysis. The XmlDocument class represents an XML document using the Document Object Model (DOM). The XmlNodeReader class is used to read the XML DOM tree stored in the XmlDocument.

System Requirements

The application will work on .NET SDK RTM. The article assumes the reader understands XML and has some knowledge of XSL, has previously used forms and controls to construct a GUI, and has some knowledge of .NET Windows Forms and C#.

This article also assumes that the reader has read Creating XSLT Using C# and Windows Forms, Part 1, which includes necessary background and overview information on XML, XSLT, and XML in .NET, as well as detailed discussion on the development of the XSLT wizard for structured data XML.

An Extended XSLT Wizard

Taking the structured data XSLT wizard from Part 1 of this article as the starting point, we now want to add the capability to produce an XSL transformation for any well-formed input XML document. By "well-formed" we mean that the XML is structured such that each start element is closed with a corresponding end element, for example:

<item>itemdata</item> or <br/>

and the elements are properly nested in a parent-child structure. For example, the following XML is not properly nested:

<dog><breed>chihuahua</dog></breed>

The nesting is incorrect because the <breed> start element is followed by the </dog> close element. Proper nesting for this XML would look like this:

<dog><breed>chihuahua</breed></dog>

Proper nesting of XML elements is very similar to proper nesting of common programming controls such as do , while , and for loops.

The goal is to extend the XSLT wizard such that it can create an XSL for any input XML that is well-formed. To test if a given XML document is well-formed, simply load it into a modern browser. If the XML is well-formed, it will be displayed in a default format; otherwise, an error message will be displayed.

Document XML Example

The XML listed below will be used as the document XML test case for the XSLT Wizard. The XML represents a tree structure with two different collections of items, with different sets of properties for each collection, and multiple layers of properties within one of the collections. This XML clearly cannot be easily represented in a simple table. It does not have a consistent set of elements at each child node level. The child element structure for each <dog> is very different from the child element structure for each <cat>. So, there is no convenient automated formula for selecting which elements would become the columns of a table. This XML is an example of the "document" type of XML discussed in the XSLT specification. Since it is not the structured data type of XML, which can easily be represented as a table of items and a fixed list of properties for each item, it cannot be transformed using the Part 1 version of the XSLT wizard.

<?xml version='1.0'?>
<pets>
  <title>My Favorite Pets</title>
  <dogs>
    <heading>Dogs</heading>
    <dog>
      <breed>chihuahua</breed>
      <info>
        <class>toy</class>
        <measurements>
          <weight>5</weight>
          <height>7</height>
          <length>14</length>
        </measurements>
        <color>Chihuahuas are most often tan in color, but there are
many variations, including dark brown.</color>
        <bark>The bark of a chihuahua can be a very annoying yip-yap.
On rare occasions a chihuahua may howl.</bark>
        <personality>Chihuahuas have a reputation for being nasty,
but they are often very lovable to their owners.</personality>
        <comment>A chihuahua is probably a bad choice for a family
with young children.</comment>
        <comment>An important point: chihuahuas are one-family dogs.
They do not adapt well if they are sent away to a new owner after
they have already become accustomed to their original owner.</comment>
      </info>
    </dog>
    <dog>
      <breed>beagle</breed>
      <info>
        <class>hound</class>
        <measurements>
          <weight>25</weight>
          <height>14</height>
          <length>26</length>
        </measurements>
        <color>Tricolor (brown, black, white) is the most typical for beagles.</color>
        <bark>The beagle's excited bark is an easily recognizable howl.
They also have a variety of other barks, used for warding off
neighbors working in their yards, and also for general barking 
when there's nothing better to do.</bark>
        <personality>The beagle is a very even-tempered breed. It loves
its family, and will tolerate a reasonable amount of unintended
abuse from younger children.</personality>
        <comment>The beagle is an excellent family watchdog. It gets to
know who is a friend of the family, but will always bark at 
strangers.</comment>
        <comment>Beagles are also excellent hunting dogs. Unfortunately
they will sometimes hunt (and eat) small family pets.</comment>
      </info>
    </dog>
    <dog>
      <breed>golden retriever</breed>
      <info>
        <class>retriever</class>
        <measurements>
          <weight>90</weight>
          <height>29</height>
          <length>47</length>
        </measurements>
        <color>Golden retrievers are named for their golden fur.</color>
        <bark>The bark is a big "ruff!"</bark>
        <personality>It's hard to find a more friendly dog than a Golden Retriever.</personality>
        <comment>Goldens will typically wag their tails when a stranger approaches.</comment>
        <comment>A big golden retriever must be trained; otherwise, they can knock people
onto the ground, pull their children on the leash as they dash to say hello to 
the neighborhood children, etc.</comment>
      </info>
    </dog>
  </dogs>
  <cats>
    <heading>Cats</heading>
    <cat>
      <breed>siamese</breed>
      <info>
        <fur>short</fur>
        <personality>You know cats!</personality>
      </info>
    </cat>
    <cat>
      <breed>angora</breed>
      <info>
        <fur>long</fur>
        <personality>You know cats!</personality>
      </info>
    </cat>
    <cat>
      <breed>American Shorthair</breed>
      <info>
        <fur>short</fur>
        <personality>You know cats!</personality>
      </info>
    </cat>
  </cats>
</pets>

Windows Forms UI

To add the capability for transforming document XSL, the Windows Forms user interface is expanded, with many new controls added to provide the user with options for configuring document XML transformations.

Image 1

The upper section of the GUI still processes the input XML file, while the bottom section performs the XSLT transformation of the input XML into an output HTML document. The middle section of the GUI is changed to provide separate paths for generating XSLs for structured data XML and document XML. The structured data XML controls from the Part 1 wizard are moved to the left side of the window (beneath Generate Data XSL), and the Generate XSL button is renamed Generate Data XSL. The right side of the window (beneath Generate Document XSL) contains new controls that allow the user to configure the XSL to be generated for document XML.

Core Code

The core custom code for the Generating Document XSL path is contained in the new ProcessDoc method and in the events code for the controls and the Generate Doc XSL button. The first major code change is at the end of buttonOpenXML_Click(). Here we change the XML characterization messages to reflect the new capability for generating an XSL for generic document XML:

             if (uniformData)
             {
               str = str + "The XML is uniform, suggesting that this " +
                "XML represents structured data. ";
                int tableRow = xmlDepth-2;
                str = str + "The lowest level elements probably " +
                   "represent the properties for each <" + 
                   levelNames[tableRow] + ">. ";
                str = str + "An XSLT that transforms this data into " +
                   "an HTML table using each <" + levelNames[tableRow] + 
                   "> element as a row, ";
                str = str + "with the level " + xmlDepth + " elements " +
                   "being the columns, is recommended. If a tabular " +
                   "output format is not desired, the document XSL " +
                   "option can be used.";
              }
              else
              {
                str = str + "This XML appears to represent a document, " +
                   "rather than a structured set of data. ";
                str = str + "Since the data cannot be conveniently " +
                   "represented in a single table, the data XSL " +
                   "option is disabled.";
              }
              
              //display the characterization in the large text box,
              //and set the XML depth text box accordingly
              textBoxXmlDesc.Text = str;
              textBoxXsltDepth.Text = xmlDepth.ToString();
              //textBoxXsltDepth.Enabled = true;

              //if this XML is the type of uniform structured data XML 
              //for which the wizard can construct an XSL, enable the 
              //controls that let the user generate a data XSL 
              if (uniformData)
              {
                checkBoxData.Checked = true;
                buttonGenXsl.Enabled = true;
              }
              else
              {
                checkBoxData.Checked = false;
              }

              //set the default XSL file name
              textBoxXslFile.Enabled = true;
              str = textBoxXMLFile.Text;
              str = str.Substring(0,str.Length-2) + "sl";
              textBoxXslFile.Text = str;
             }
      }
      //catch XMLTextReader error and display message
      catch(Exception xrErr) 
      {
             MessageBox.Show("attempt to read failed: "+xrErr.Message);
             return;
      }
      ProcessDoc();
      return;
   }

ProcessDoc()

At the end of buttonOpenXML_Click(), we call the new method, ProcessDoc(). ProcessDoc() analyzes and characterizes the input XML from a point of view that does not require or assume any repeated structure. The goal is to identify the elements that are available for transformation, organize them based on node depth, and define default transformation settings (to provide the user with a capability to immediately generate an XSL, without needing to touch any of the settings controls). Specifically, ProcessDoc() performs the following operations:

The XmlDocument class implements the World Wide Web Consortium (http://www.w3.org/?WROXEMPTOKEN=104402ZqcBHoVRn7SMRtRBTgKM) Document Object Model (DOM) Level 1 and Level 2 Core. In the DOM model, the full XML document is read into memory and represented as a tree structure. XmlDocument properties and methods enable the programmer to analyze the XML tree structure, determine which elements have attributes and child elements, navigate to child nodes, read node data, create new nodes, and perform many other evaluations and manipulations of the XML structure.

The XmlDocument class is ideal for a situation where the input XML structure is complex and not known in advance. In ProcessDoc() , we use the XmlDocument.Load method to load the input XML document specified by the user into the doc XmlDocument. Full utilization of the capability provided by the XmlDocument class is beyond the scope of our simple XSLT Wizard. However, in an extended version of the program the XmlDocument methods and properties could be utilized to provide highly customized XSL generation, providing the user with many potential transformations into alternative output formats.

The XmlNodeReader class is used to read the input XML after it is loaded into the doc XmlDocument. XmlNodeReader is derived from the XmlReader class. It provides fast, forward reading of XML nodes, and has capability to read nodes from an XML DOM structure. Since our analysis is focused solely on identifying the names and depths of elements that have text data that can be transformed and displayed, and we have the XML loaded into an XmlDocument DOM, XmlNodeReader is a convenient means for quickly processing the elements.

We use the NodeType property in XmlNodeReader to identify XML Element nodes. In Part 1 of this article, you'll recall seeing that we used the same property in XmlTextReader for the same purpose. Both XmlNodeReader and XmlTextReader are derived from the XmlReader class, an abstract class that contains the NodeType property. NodeType is one of the most fundamental and useful properties in the .NET XML classes. Any .NET code you write that processes XML is likely to utilize NodeType for classifying the current node and determining the necessary subsequent processing.

The Depth value for each element node containing text data is saved in the docElDepth[] array, while docElName[] stores the names of the corresponding elements, which will be made available to the user for transformation and output to the HTML document.

   private void ProcessDoc()
   {
      //create a DOM-based document container
      XmlDocument doc = new XmlDocument();
      try
      {
             //load the input XML file specified by the user
             doc.Load(textBoxXMLFile.Text);

             //create a new XmlNodeReader to read the XML
             //from the doc XmlDocument container
             XmlNodeReader nr = new XmlNodeReader(doc);
             String estr = "";
             nDocEl = 0;

             //read the input XML one node at a time
             while (nr.Read())
             {
              //store the name of each element node
              if (nr.NodeType == XmlNodeType.Element)
              {
                estr = nr.Name;
              }

              //if this node contains text data, store its element
              //name and depth (if we haven't done so already)
              if (nr.NodeType == XmlNodeType.Text)
              {
                bool foundMatch = false;
                for (int j=0; ((j<nDocEl) && !foundMatch); j++)
                {
                   if ((docElName[j] == estr) && (docElDepth[j] == nr.Depth))
                   {
                          foundMatch = true;
                   }
                }
                if (!foundMatch)
                {
                   docElName[nDocEl]=estr;
                   docElDepth[nDocEl]=nr.Depth;
                   nDocEl++;
                }
              }
             }

             //close the XmlNodeReader
             nr.Close();

             //if element nodes containing text were found,
             //create default XSLT settings for each element
             if (nDocEl > 0)
             {
              int jMaxDepth = docElDepth[0];
              int jMinDepth = docElDepth[0];
              int jDepthRange = 0;

              //create an element combo box entry for each element
              for (int j=0; j<nDocEl; j++)
              {
                comboBoxDocEl.Items.Add(docElDepth[j] + ":" + docElName[j]);
                if (docElDepth[j] > jMaxDepth) jMaxDepth = docElDepth[j];
                if (docElDepth[j] < jMinDepth) jMinDepth = docElDepth[j];
              }
              jDepthRange = jMaxDepth - jMinDepth;

              //specify default format settings for each item
              for (int j=0; j<nDocEl; j++)
              {
                elDisplay[j] = true; //display the element
                elLabel[j] = true; //do not label with element name
                elColor[j] = 0; //font color: black

                //compute default font size based on element depth
                //by default, spread the font sizes between 4 and 7;
                //if the range is zero, use font size 5 as the default
                if (jDepthRange > 0)
                {
                   elSize[j] = (jMaxDepth - docElDepth[j]) * 3 / jDepthRange;
                }
                else
                {
                   elSize[j] = 1; //value of 1 means font 5
                }
                
                   //make the top 2 level elements bold, others not
                   elBold[j] = (docElDepth[j] <= jMinDepth + 1);

                elItal[j] = false; //not italic

                //make the top level element a paragraph;
                //follow the other elements with a line break
                if (docElDepth[j] == jMinDepth)
                {
                   elNewLine[j] = 0;
                }
                else
                {
                   elNewLine[j] = 1;
                }
              }

              //enable document XSL generation controls
              comboBoxDocEl.Enabled = true;
              comboBoxFontColor.Enabled = true;
              comboBoxFontSize.Enabled = true;
              checkBoxElDsp.Enabled = true;
              checkBoxElLab.Enabled = true;
              checkBoxFontBold.Enabled = true;
              checkBoxFontItal.Enabled = true;
              comboBoxNewLine.Enabled = true;
              buttonDocXSL.Enabled = true;
             }
      }
      catch (Exception err)
      {
             MessageBox.Show("attempt to load XML failed: " + err.Message);
             return;
      }
      return;
   }

comboBoxDocEl_SelectedIndexChanged()

The Generate Document XSL user interface presents the transformation settings for the element that is currently selected in the comboBoxDocEl combo control (labeled Depth:Element in its default). Each time the user selects a different depth:element entry, the comboBoxDocEl_SelectedIndexChanged() event function is called. This function accesses the settings for the selected depth:element item and loads the other controls with the last saved settings. This allows the user to scan the depth:element list and selectively alter the transformation settings as desired.

   private void comboBoxDocEl_SelectedIndexChanged(object sender, System.EventArgs e)
   {
      int jEl = comboBoxDocEl.SelectedIndex;

      checkBoxElDsp.Checked = elDisplay[jEl];
      checkBoxElLab.Checked = elLabel[jEl];
      checkBoxFontBold.Checked = elBold[jEl];
      checkBoxFontItal.Checked = elItal[jEl];
      comboBoxFontColor.SelectedIndex = elColor[jEl];
      comboBoxFontSize.SelectedIndex = elSize[jEl];
      comboBoxNewLine.SelectedIndex = elNewLine[jEl];
   }

buttonDocXSL_Click()

After the user has selected the styles for transforming the document XML, the Generate Doc XSL button is clicked. This event invokes buttonDocXSL_Click() , which does the following:

The XSL generated by buttonDocXSL_Click() consists of a heading template and individual templates for each depth:element combination found in the input XML document. HTML tags are inserted before and/or after the data for each element is displayed, depending on the settings selected by the user for that particular element. A simple StreamWriter class is used to perform the write.

As in buttonGenXsl_Click() , an XSL select string consisting of a concatenated sequence of "/* " characters is created to ensure that the element name at the correct depth is accessed by each individual element template. For example, to transform an element named ' item' located at depth 3 (that is, 2 layers of child nodes beneath the document level node), we need to construct the following template match statement: <xsl:template match='/*/*/item'>. The XSL listed near the end of this article is a complete example of what is produced by buttonDocXsl_Click().

   private void buttonDocXSL_Click(object sender, System.EventArgs e)
   {

      // write the XSL file; catch any errors writing the file
      try
      {
             String str;
             StreamWriter sw = File.CreateText(textBoxXslFile.Text);

             //write the XSL and HTML heading elements, and the
             //HEAD/TITLE element
             sw.WriteLine("<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>");
             sw.WriteLine("<xsl:template match='/*'>");
             sw.WriteLine("<html>");
             sw.WriteLine("<head><title>" + textBoxPageTitle.Text + 
              "</title></head>");

             //write the HTML BODY element based on the color selected 
             //by the user
             str="";
             if (comboBoxPageColor.SelectedIndex > -1)
             {
              str=" BGColor='" + 
                myColors[comboBoxPageColor.SelectedIndex] + "'";
             }
             sw.WriteLine("<body" + str + ">");

             //write the title selected by the user as an H3 HTML heading
             sw.WriteLine("<h3>" + textBoxPageTitle.Text + "</h3>");

             //apply all templates and close the HTML document
             sw.WriteLine("<xsl:apply-templates/>");
             sw.WriteLine("</body>");
             sw.WriteLine("</html>");
             sw.WriteLine("</xsl:template>");

             //write the template for each text element
             for (int j=0; j<nDocEl; j++)
             {
              //specify the element depth and name
              str = "<xsl:template match='";
              for (int i=0; i<docElDepth[j]-1; i++) str = str + "/*";
              str = str + "/" + docElName[j] + "'>";
              sw.WriteLine(str);

              //if the element is to be displayed, write the settings
              if (elDisplay[j])
              {
                //new line setting (preceding element)
                switch (elNewLine[j])
                {
                   case 0: //paragraph
                          sw.WriteLine("<p>");
                          break;
                   case 1: //start new line
                          sw.WriteLine("<br/>");
                          break;
                   case 2: //new line after
                          break;
                   case 3: //no new line
                          break;
                }

                //font color and size
                str = "<font color='" + fontColors[elColor[j]] +
                   "' size = '" + comboBoxFontSize.Items[elSize[j]].ToString() +
                   "'>";
                sw.WriteLine(str);

                //bold and italics
                if (elBold[j]) sw.WriteLine("<b>");
                if (elItal[j]) sw.WriteLine("<i>");

                //element label, underlined
                if (elLabel[j])
                {
                   sw.WriteLine("<u>"+docElName[j]+"</u>: "); 
                }

                //write the element value
                sw.WriteLine("<xsl:value-of select='.'/>");

                //close setting elements
                if (elItal[j]) sw.WriteLine("</i>");
                if (elBold[j]) sw.WriteLine("</b>");
                sw.WriteLine("</font>");

                //new line setting (after element)
                switch (elNewLine[j])
                {
                   case 0: //paragraph
                          sw.WriteLine("</p>");
                          break;
                   case 1: //start new line
                          break;
                   case 2: //new line after
                          sw.WriteLine("<br/>");
                          break;
                   case 3: //no new line
                          break;
                }
              }

              //close the template element
              sw.WriteLine("</xsl:template>");

             }

             //close the stylesheet element
             sw.WriteLine("</xsl:stylesheet>");

             //the XSL file is complete, so close the StreamWriter
             sw.Close();

             //tell the user the XSL write was successful
             MessageBox.Show("File " + textBoxXslFile.Text + 
              " was successfully written.");
              
             //enable the transform controls
             str = textBoxXMLFile.Text;
             str = str.Substring(0,str.Length-3) + "html";
             textBoxOutFile.Text = str;
             textBoxOutFile.Enabled = true;
             buttonTransform.Enabled = true;
      }
      catch (Exception err)
      {
             MessageBox.Show("An error occurred while writing the XSL: " 
              + err.Message);
      }

   } 

Using the XSLT Wizard

Running the XSLT Wizard to transform document XSL is very easy. First, enter the input XML file name and click "Open XML File ". The characterization of the XML will appear in the text box beneath the "Open XML File " button, and the "Generate Document XSL " controls will be enabled.

Next, select the desired "Generate Document XSL " style options for the output HTML document, enter an XSL File Name, and click "Generate Doc XSL ":

Image 2

The following XSL is one example of what can be generated from the doc.xml listed above:

<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:template match='/*'>
<html>
<head><title></title></head>
<body BGColor='lt.blue'>
<h3></h3>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match='/*/title'>
<p>
<font color='black' size = '6'>
<b>
<xsl:value-of select='.'/>
</b>
</font>
</p>
</xsl:template>
<xsl:template match='/*/*/heading'>
<br/>
<font color='black' size = '6'>
<b>
<xsl:value-of select='.'/>
</b>
</font>
</xsl:template>
<xsl:template match='/*/*/*/breed'>
<br/>
<font color='black' size = '5'>
<b>
<i>
<xsl:value-of select='.'/>
</i>
</b>
</font>
</xsl:template>
<xsl:template match='/*/*/*/*/class'>
<br/>
<font color='black' size = '4'>
<u>class</u>: 
<xsl:value-of select='.'/>
</font>
</xsl:template>
<xsl:template match='/*/*/*/*/*/weight'>
<br/>
<font color='black' size = '4'>
<u>weight</u>: 
<xsl:value-of select='.'/>
</font>
</xsl:template>
<xsl:template match='/*/*/*/*/*/height'>
<font color='black' size = '4'>
<u>height</u>: 
<xsl:value-of select='.'/>
</font>
</xsl:template>
<xsl:template match='/*/*/*/*/*/length'>
<font color='black' size = '4'>
<u>length</u>: 
<xsl:value-of select='.'/>
</font>
</xsl:template>
<xsl:template match='/*/*/*/*/color'>
<br/>
<font color='black' size = '4'>
<u>color</u>: 
<xsl:value-of select='.'/>
</font>
</xsl:template>
<xsl:template match='/*/*/*/*/bark'>
<p>
<font color='black' size = '4'>
<xsl:value-of select='.'/>
</font>
</p>
</xsl:template>
<xsl:template match='/*/*/*/*/personality'>
<p>
<font color='black' size = '4'>
<xsl:value-of select='.'/>
</font>
</p>
</xsl:template>
<xsl:template match='/*/*/*/*/comment'>
<p>
<font color='black' size = '4'>
<xsl:value-of select='.'/>
</font>
</p>
</xsl:template>
<xsl:template match='/*/*/*/*/fur'>
<br/>
<font color='black' size = '4'>
<u>fur</u>: 
<xsl:value-of select='.'/>
</font>
</xsl:template>
</xsl:stylesheet>

Finally, enter an Output File name for the transformed data and click "Transform." The following HTML output document is produced using the XSL listed above:

<html>
  <head>
    <META http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>
    </title>
  </head>
  <body BGColor="lt.blue">
    <h3>
    </h3>
    <p>
      <font color="black" size="6">
        <b>My Favorite Pets</b>
      </font>
    </p>
    <br>
    <font color="black" size="6">
      <b>Dogs</b>
    </font>
    <br>
    <font color="black" size="5">
      <b>
        <i>chihuahua</i>
      </b>
    </font>
    <br>
    <font color="black" size="4">
      <u>class</u>: 
toy</font>
    <br>
    <font color="black" size="4">
      <u>weight</u>: 
5</font>
    <font color="black" size="4">
      <u>height</u>: 
7</font>
    <font color="black" size="4">
      <u>length</u>: 
14</font>
    <br>
    <font color="black" size="4">
      <u>color</u>: 
Chihuahuas are most often tan in color, but there are
many variations, including dark brown.</font>
    <p>
      <font color="black" size="4">The bark of a chihuahua can be a very annoying yip-yap.
On rare occasions a chihuahua may howl.</font>
    </p>
    <p>
      <font color="black" size="4">Chihuahuas have a reputation for being nasty,
but they are often very lovable to their owners.</font>
    </p>
    <p>
      <font color="black" size="4">A chihuahua is probably a bad choice for a family
with young children.</font>
    </p>
    <p>
      <font color="black" size="4">An important point: chihuahuas are one-family dogs.
They do not adapt well if they are sent away to a new owner after
they have already become accustomed to their original owner.</font>
    </p>
    <br>
    <font color="black" size="5">
      <b>
        <i>beagle</i>
      </b>
    </font>
    <br>
    <font color="black" size="4">
      <u>class</u>: 
hound</font>
    <br>
    <font color="black" size="4">
      <u>weight</u>: 
25</font>
    <font color="black" size="4">
      <u>height</u>: 
14</font>
    <font color="black" size="4">
      <u>length</u>: 
26</font>
    <br>
    <font color="black" size="4">
      <u>color</u>: 
Tricolor (brown, black, white) is the most typical for beagles.</font>
    <p>
      <font color="black" size="4">The beagle's excited bark is an easily recognizable howl.
They also have a variety of other barks, used for warding off
neighbors working in their yards, and also for general barking 
when there's nothing better to do.</font>
    </p>
    <p>
      <font color="black" size="4">The beagle is a very even-tempered breed. It loves
its family, and will tolerate a reasonable amount of unintended
abuse from younger children.</font>
    </p>
    <p>
      <font color="black" size="4">The beagle is an excellent family watchdog. It gets to
know who is a friend of the family, but will always bark at 
strangers.</font>
    </p>
    <p>
      <font color="black" size="4">Beagles are also excellent hunting dogs. Unfortunately
they will sometimes hunt (and eat) small family pets.</font>
    </p>
    <br>
    <font color="black" size="5">
      <b>
        <i>golden retriever</i>
      </b>
    </font>
    <br>
    <font color="black" size="4">
      <u>class</u>: 
retriever</font>
    <br>
    <font color="black" size="4">
      <u>weight</u>: 
90</font>
    <font color="black" size="4">
      <u>height</u>: 
29</font>
    <font color="black" size="4">
      <u>length</u>: 
47</font>
    <br>
    <font color="black" size="4">
      <u>color</u>: 
Golden retrievers are named for their golden fur.</font>
    <p>
      <font color="black" size="4">The bark is a big "ruff!"</font>
    </p>
    <p>
      <font color="black" size="4">It's hard to find a more friendly dog than a Golden Retriever.</font>
    </p>
    <p>
      <font color="black" size="4">Goldens will typically wag their tails when a stranger approaches.</font>
    </p>
    <p>
      <font color="black" size="4">A big golden retriever must be trained; otherwise, they can knock people
onto the ground, pull their children on the leash as they dash to say hello to 
the neighborhood children, etc.</font>
    </p>
    <br>
    <font color="black" size="6">
      <b>Cats</b>
    </font>
    <br>
    <font color="black" size="5">
      <b>
        <i>siamese</i>
      </b>
    </font>
    <br>
    <font color="black" size="4">
      <u>fur</u>: 
short</font>
    <p>
      <font color="black" size="4">You know cats!</font>
    </p>
    <br>
    <font color="black" size="5">
      <b>
        <i>angora</i>
      </b>
    </font>
    <br>
    <font color="black" size="4">
      <u>fur</u>: 
long</font>
    <p>
      <font color="black" size="4">You know cats!</font>
    </p>
    <br>
    <font color="black" size="5">
      <b>
        <i>American Shorthair</i>
      </b>
    </font>
    <br>
    <font color="black" size="4">
      <u>fur</u>: 
short</font>
    <p>
      <font color="black" size="4">You know cats!</font>
    </p>
  </body>
</html>

Viewed in a web browser, the HTML document looks like this:

Image 3

It is very convenient to tune the output result by keeping the XSLT Wizard and the browser side by side on the screen, altering settings and generating new XSLs, then refreshing the browser view, until a suitable output format is attained.

Further Work

The XSLT Wizard provides a capability to generate XSLs and perform XSL transformations for both structured data XML and less structured or unstructured document XML. However, the number of possible extensions is unlimited. Virtually any presentation capability provided by HTML could be implemented. The present wizard does not process attributes - the addition of options for transforming XML attributes would be valuable for certain input XML files.

Conclusion

We have developed an XSLT Wizard using C#, Windows Forms, and several key .NET XML classes. The Wizard performs an automated characterization of an arbitrary input XML file to determine if it is structured data XML that represents a group of items with a specific list of parameters for each item, or the less structured document type of XML. In either case, a document-oriented XSLT can be generated, using styling options selected by the user. In addition, if the XML is of the structured data type, we can generate an XSL that transforms the XML into an HTML table.

Please rate this article using the form below. By telling us what you like and dislike about it we can tailor our content to meet your needs.

Article Information
Author Kevin Farnham
Technical Editors John R. Chapman, Vickie Pring
Project Manager Helen Cuthill
Reviewers Andrew Krowczyk, John Boyd Nolan

If you have any questions or comments about this article, please contact the technical editor.

 
 
   
  RATE THIS ARTICLE
  Please rate this article (1-5). Was this article...
 
 
Useful? No Yes, Very
 
Innovative? No Yes, Very
 
Informative? No Yes, Very
 
Brief Reader Comments?
Your Name:
(Optional)
 
  USEFUL LINKS
  Related Tasks:
 
 
   
  Related ASPToday Articles
   
  • Creating XSLT Using C# and Windows Forms, Part 1 (February 8, 2002)
  •  
           
     
     
      Related Sources
     
  • “XML in .NET: .NET Framework XML Classes and C# Offer Simple, Scalable Data Manipulation”, MSDN Magazine, January 2001: http://msdn.microsoft.com/msdnmag/issues/01/01/xml/xml.asp
  • “Extensible Stylesheet Language (XSL) Version 1.0”: http://www.w3.org/TR/xsl/
  • “XSL Transformations (XSLT) Version 1.0”: http://www.w3.org/TR/xslt
  • Professional Windows Forms: http://www.wrox.com/ACON11.asp?ISBN=1861005547
  •  
     
           
      Search the ASPToday Living Book   ASPToday Living Book
     
      Index Full Text Advanced 
     
     
           
    HOME | SITE MAP | INDEX | SEARCH | REFERENCE | FEEDBACK | ADVERTISE | SUBSCRIBE
    .NET Framework Components Data Access DNA 2000 E-commerce Performance
    Security Admin Site Design Scripting XML/Data Transfer Other Technologies

     
    ASPToday is brought to you by Wrox Press (http://www.asptoday.com/OffSiteRedirect.asp?Advertiser=www.wrox.com/&WROXEMPTOKEN=104402ZqcBHoVRn7SMRtRBTgKM). Please see our terms and conditions and privacy policy.
    ASPToday is optimised for Microsoft Internet Explorer 5 browsers.
    Please report any website problems to webmaster@asptoday.com. Copyright © 2002 Wrox Press. All Rights Reserved.