Using XSLT and .NET to Manipulate XML Files

Using XSLT and .NET to Manipulate XML Files

Introduction

XML Stylesheet Transformations (XSLT) is defined as a language for transforming source XML documents into another document formats using XML Path Language (XPath) as a query language. This is particularly useful when incoming or outgoing XML documents do not match the document type expected by the target system.

In an XSL transformation, an XSLT processor reads both an XML document and an XSLT style sheet. Based on the instructions the processor finds in the XSLT style sheet, it outputs a new XML document or fragment. There’s also special support for outputting HTML. With some effort, most XSLT processors can also be made to output essentially random text, though XSLT is designed primarily for XML-to-XML and XML-to-HTML transformations.

Discussion

XSLT operates by transforming one XML tree into another XML tree. More precisely, an XSLT processor accepts as input a tree represented as an XML document and produces as output a new tree, also represented as an XML document. Hence, XSLT assumes that three documents are in use: the source document, the XSLT stylesheet document and the result document. The source document is simply a well-formed XML document that provides the input for the transformation. The stylesheet document is an XML document that uses the XSLT vocabulary for expressing transformation rules. The result document is a text document that is produced by running the source document through the transformations found in XSLT stylesheet.

The XSLT transformation can be handled in the .NET platform, which is demonstrated by the code below:

using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;

public class TransformXML
{
    //This will transform xml document using xslt and produce result xml document
    //and display it

    public static void Main(string[] args)
    {
        try
        {
            XPathDocument myXPathDocument = new XPathDocument(sourceDoc);
            XslTransform myXslTransform = new XslTransform();
            XmlTextWriter writer = new XmlTextWriter(resultDoc, null);
            myXslTransform.Load(xsltDoc);
            myXslTransform.Transform(myXPathDocument, null, writer);
            writer.Close();
            StreamReader stream = new StreamReader (resultDoc);
            Console.Write("**This is result document**\n\n");
            Console.Write(stream.ReadToEnd());
        }
        catch (Exception e)
        {
            Console.WriteLine ("Exception: {0}", e.ToString());
        }
    }
}

Note: this code will run in Console application

This sample relies on an XPathDocument class named myXPathDocument that loads the XML document that will be transformed, and an XslTransform class named myXslTransform that performs the transformation from the source document into another document, which is a result document. The XslTransform class, found in the System.Xml.Xsl namespace, is the XSLT processor that implements the XSLT version 1.0 recommendation.

The code above is handling the XSLT output with the XmlTextWriter class, which functionality inherited from the XmlWriter abstract class, is useful for writing out the character streams. In this sample, the XmlTextWriter takes 2 parameters which are the filename as a String and the Encoding which in this case is defined as null. Once an XmlTextWriter object is created, it writes the transformed file to the disk. The file that is created named resultDoc, which is the first parameter passed to the XmlTextWriter constructor.

In order to perform a transformation using XslTransform, first create an XslTransform object and load it with the desired XSLT document (by calling Load). The Load method of XslTransform class loads the XSL Stylesheet from disk called xsltDoc. Finally, the transform is executed by calling Transform method of the XslTransform class object. Transform method takes the XML document object and the XmlTextWriter objects as parameters. The second parameter of the Transform method is used to pass additional runtime arguments, it is left to null. After the transform is complete, XmlTextWriter object is closed to complete the writing of the new XML document file to the disk.

Reading the file back in is done by creating a stream for reading and using the StreamReader to interpret the contents of the file. Finally, it will display the contents of the result document on the screen by calling the method Write from Console class.

There is an alternative way of handling the transformation. Instead of having to create and load the input source document and writing to a file stream, user can simply use the Transform method of XslTransform to load a document and write to file directly by loading an XML document from file, applying the XSLT file, and writing the result to the file as shown in the code below:

XslTransform myXslTransform = new XslTransform();
myXslTransform.Load(xsltDoc);
myXslTransform.Transform(sourceDoc, resultDoc);

Conclusion

XSLT, the extensible stylesheet language for transformations, is a language that provides the mechanism to transform and manipulate XML data. It is used to transform XML documents into another documents, for example other XML document, HTML document or text document. XSLT processors parse the input XML document, as well as the XSLT stylesheet and then process the instructions found in the XSLT stylesheet, using the elements from input XML document. During the processing of the XSLT instructions, a structured XML output is created.

In .NET framework, this transformation is handled using the Load and Transform method from the XslTransform class. Initially, an XslTransform object is instantiated, which is the engine to perform XSLT transformations on XML documents in the .NET framework. The Loadmethod of the XslTransform class is called to load the XSL stylesheet from disk. Finally, the Transform method is executed, takes the XPathDocument and XmlTextWriter object as parameters. On the other hand, user can call the Transform method to initiate the transformation and passing in the source XML document and the transformed XML document name. Essentially, the XSLT processor processes the input document, applies the stylesheet and produces the result document.

Downloads

There are two sets of files associated with this article. The first is a Windows forms application and includes much of the code listed here. There is also a smaller command-line version that you may find easier to understand.


Appendix I : C# Source Code Listing

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;

namespace Transformer
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.TextBox txtSource;
        private System.Windows.Forms.TextBox txtXslt;
        private System.Windows.Forms.Label lblSource;
        private System.Windows.Forms.Label lblXslt;
        private System.Windows.Forms.Button btnGenerate;
        private String sourceDoc = "";
        private String xsltDoc = "";
        private String resultDoc = "result.xml";
        private System.Windows.Forms.TextBox txtResult;
        private System.Windows.Forms.Button btnReset;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.txtSource = new System.Windows.Forms.TextBox();
            this.txtXslt = new System.Windows.Forms.TextBox();
            this.lblSource = new System.Windows.Forms.Label();
            this.lblXslt = new System.Windows.Forms.Label();
            this.btnGenerate = new System.Windows.Forms.Button();
            this.txtResult = new System.Windows.Forms.TextBox();
            this.btnReset = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // txtSource
            // 
            this.txtSource.Location = new System.Drawing.Point(136, 16);
            this.txtSource.Name = "txtSource";
            this.txtSource.Size = new System.Drawing.Size(136, 22);
            this.txtSource.TabIndex = 0;
            this.txtSource.Text = "";
            // 
            // txtXslt
            // 
            this.txtXslt.Location = new System.Drawing.Point(136, 48);
            this.txtXslt.Name = "txtXslt";
            this.txtXslt.Size = new System.Drawing.Size(136, 22);
            this.txtXslt.TabIndex = 1;
            this.txtXslt.Text = "";
            // 
            // lblSource
            // 
            this.lblSource.Location = new System.Drawing.Point(16, 16);
            this.lblSource.Name = "lblSource";
            this.lblSource.TabIndex = 2;
            this.lblSource.Text = "Source XML";
            // 
            // lblXslt
            // 
            this.lblXslt.Location = new System.Drawing.Point(16, 48);
            this.lblXslt.Name = "lblXslt";
            this.lblXslt.TabIndex = 3;
            this.lblXslt.Text = "XSLT";
            // 
            // btnGenerate
            // 
            this.btnGenerate.Location = new System.Drawing.Point(40, 88);
            this.btnGenerate.Name = "btnGenerate";
            this.btnGenerate.TabIndex = 4;
            this.btnGenerate.Text = "Generate";
            this.btnGenerate.Click += new System.EventHandler(this.btnGenerate_Click);
            // 
            // txtResult
            // 
            this.txtResult.Location = new System.Drawing.Point(16, 120);
            this.txtResult.Multiline = true;
            this.txtResult.Name = "txtResult";
            this.txtResult.ReadOnly = true;
            this.txtResult.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.txtResult.Size = new System.Drawing.Size(264, 152);
            this.txtResult.TabIndex = 5;
            this.txtResult.Text = "";
            // 
            // btnReset
            // 
            this.btnReset.Location = new System.Drawing.Point(160, 88);
            this.btnReset.Name = "btnReset";
            this.btnReset.TabIndex = 6;
            this.btnReset.Text = "Reset";
            this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
            this.ClientSize = new System.Drawing.Size(292, 288);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
            this.btnReset,
            this.txtResult,
            this.btnGenerate,
            this.lblXslt,
            this.lblSource,
            this.txtXslt,
            this.txtSource});
            this.Name = "Form1";
            this.Text = "XML Transformer";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

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

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

            if ((txtSource.Text.Trim() == "") || (txtXslt.Text.Trim() == "")) 
            {
                MessageBox.Show("Enter the filename!", "File Name Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                
            }

            try
            {

                XPathDocument myXPathDocument = new XPathDocument (sourceDoc);
                XslTransform myXslTransform = new XslTransform();
        
                XmlTextWriter writer = new XmlTextWriter(resultDoc, null);
                myXslTransform.Load(xsltDoc);

                myXslTransform.Transform(myXPathDocument, null, writer);
                writer.Close();

                StreamReader stream = new StreamReader (resultDoc);
                txtResult.Text = stream.ReadToEnd();
  
            }

            catch (FileNotFoundException filexc)
            {
                MessageBox.Show("File Not Found!", "File Not Found Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }


            catch (Exception exc)
            {
                Console.WriteLine ("Exception: {0}", exc.ToString());
            }

        }

        private void btnReset_Click(object sender, System.EventArgs e)
        {
            txtSource.Text = "";
            txtXslt.Text = "";
            txtResult.Text = "";
        }
    }
}

Appendix II: XML Source Code Listing

<?xml version='1.0'?>
<!-- This file represents a fragment of a book store inventory database -->
<bookstore>
  <book genre="autobiography" publicationdate="1981" ISBN="1-861003-11-0">
    <title>The Autobiography of Benjamin Franklin</title>
    <author>
      <first-name>Benjamin</first-name>
      <last-name>Franklin</last-name>
    </author>
    <price>8.99</price>
  </book>
  <book genre="novel" publicationdate="1967" ISBN="0-201-63361-2">
    <title>The Confidence Man</title>
    <author>
      <first-name>Herman</first-name>
      <last-name>Melville</last-name>
    </author>
    <price>11.99</price>
  </book>
  <book genre="philosophy" publicationdate="1991" ISBN="1-861001-57-6">
    <title>The Gorgias</title>
    <author>
      <name>Plato</name>
    </author>
    <price>9.99</price>
  </book>
</bookstore>

Appendix III: XSL Source Code Listing

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
    <root>
        <xsl:apply-templates/>
    </root>
    </xsl:template>

    <xsl:template match="bookstore">
    <!-- Prices and books -->
        <bookstore>
            <xsl:apply-templates select="book"/>
        </bookstore>
    </xsl:template>

    <xsl:template match="book">
        <book>
            <xsl:attribute name="ISBN">
                <xsl:value-of select="@ISBN"/>
            </xsl:attribute>
            <price><xsl:value-of select="price"/></price><xsl:text>
            </xsl:text>
        </book>
    </xsl:template>

</xsl:stylesheet>

Appendix IV: Test Strategy

Instructions:

  1. Type in the XML file name (without extension)
  2. Type in the XSL file name (without extension)
  3. Click Generate button

Test Scenario Objective:

Test if the XML file given is transformed to new XML document by applying the XSL file

Test Cases

1. Type in valid XML filename and valid XSL filename

Expected Result: The file is created and the contents of the file are displayed in the Result Text Box
Actual Result: The file is created and the contents of the file are displayed in the Result Text Box

2. Type in invalid XML filename or invalid XSL filename

Expected Result: Pop up message box, telling user that File Not Found
Actual Result: Pop up message box, telling user that File Not Found


References

– Box, D., Skonnard, A., Lam, J. (2000), ‘XSL Transformations: XSLT Alleviates XML Schema Incompatibility Headaches’, MSDN Magazine August 2000
– Gardner, J.R. (2002), XSLT & XPATH: A Guide to XML Transformations, Prentice Hall, New Jersey, USA
– Harold, E.R. (2001), XML Bible 2nd Edition, Hungry Minds, USA
– Ryan, B. (2002), Read Less-Learn More C#, Hungry Minds, USA
– Skonnard, A. (2001), ‘XML in .NET: .NET Framework XML Classes and C# Offer Simple, Scalable Data Manipulation’, MSDN Magazine January 2001
– Turtschi, A., et.al (2002), C# .NET Web Developer Guide, Syngress Publishing Inc., Rockland, MA, USA
– Wahlin, D. (2002), ‘4 XSLT Output Tips’, XML & Web Services Magazine April/May 2002
– MSDN Home website, http://msdn.microsoft.com/default.asp
– Programmers Heaven website, http://www.programmersheaven.com/
– Perfect XML website, http://www.perfectxml.com/
– C# Corner website, http://www.c-sharpcorner.com/

Related posts

SOAP Soup

Introduction Simple Object Access Protocol is one of the neatest XML based technologies to be introduced as of late, yet many people are still trying to get a handle on all of the new terms and acronyms that SOAP has uncovered. This article is written to help you dig through the SOAP...

Read More

Using XML to build an ASP+ config.web Editor

Introduction ASP+ configuration information is stored in XML-based configuration files. Using built-in features of IIS 5.0 and IE 5.0 such as the FileSystemObject, the XML Document Object Model (DOM) and XML Data Islands, we can easily develop a rich tool for modifying and editing these configuration files. In this...

Read More

Saving HTML Form Data to XML

Introduction This example assumes that you are familiar with ASP, XML and HTML 4.0. Storing your form submissions in XML Usually form submissions in ASP are written to some sort of database management system. However, if you need your form submission data to be more portable, it can be...

Read More