Click here to Skip to main content
Click here to Skip to main content

Serializing XML with stylesheet

, 25 Apr 2006
Rate this:
Please Sign up or sign in to vote.
An explanation of how to serialize an object and include an XML-stylesheet processing instruction.

Introduction

The Microsoft .NET framework makes it very easy to serialize an object to XML. It has its shortcomings which I won't go into here, but all-in-all, it is quite useful. Something I've wanted to do for some time now is to write out (serialize) an object in XML format while including a stylesheet reference..

Description of the Problem

For this article, I am using a simple class called Dictionary. It is just a list of words, where the Word class is just a combination of a value (the word) and its definition. Here is the Dictionary class:

using System;
using System.Collections.Generic;
using System.Text;

namespace WriteXmlWithStyle
{
    [Serializable]
    public class Dictionary
    {
        List<Word> m_Words = 
               new List<Word>();

        public List<Word> Words
        {
            get { return m_Words; }
            set { m_Words = value; }
        }
    }
}

And here is the Word class:

using System;
using System.Collections.Generic;
using System.Text;

namespace WriteXmlWithStyle
{
    [Serializable]
    public class Word
    {
        private string m_strWord;
        private string m_strDefinition;

        public Word()
        {
        }

        public Word(string word, string def)
        {
            m_strWord = word;
            m_strDefinition = def;
        }

        public string Value
        {
            get { return m_strWord; }
            set { m_strWord = value; }
        }

        public string Definition
        {
            get { return m_strDefinition; }
            set { m_strDefinition = value; }
        }
    }
}

It doesn't really matter what objects we are serializing, but it helps to get a look at these before we start looking at them in their serialized form.

Objects are normally serialized to XML like this:

private void SerializeWithoutStylesheet(Dictionary 
                         dictionary, Stream stream)
{
    StreamWriter writer = new StreamWriter(stream);
    try
    {
        XmlSerializer serializer = 
            new XmlSerializer(typeof(Dictionary));
        serializer.Serialize(writer, dictionary);
    }
    finally
    {
        writer.Flush();
    }
}

which produces an easy to read XML document like this:

<?xml version="1.0" encoding="utf-8"?>
<Dictionary 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Words>
    <Word>
      <Value>House</Value>
      <Definition>A place where people 
              live providing shelter</Definition>
    </Word>
    <Word>
      <Value>Car</Value>
      <Definition>A device to transport people</Definition>
    </Word>
    <Word>
      <Value>Wood</Value>
      <Definition>Part of a tree</Definition>
    </Word>
    <Word>
      <Value>Serializer</Value>
      <Definition>An object for transforming another object to or
          from a linear sequence of bytes</Definition>
    </Word>
  </Words>
</Dictionary>

OK. Now, we get to the cool stuff. XML stylesheets give us the ability to transform this XML into another form. Normally, when you open up an XML file in a web browser, you see the raw XML (albeit formatted):

However, we can transform the XML into HTML (using a stylesheet), to produce this instead:

The Solution

In order to write out a stylesheet reference, we need to do two things:

  1. Create the stylesheet that does the transformation, and
  2. Add a processing instruction to the XML to reference the stylesheet.

Here is the stylesheet source to produce the above table:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    <html>
      <head>
        <title>My Dictionary</title>
        <link href="Dictionary.css" 
             rel="stylesheet" 
             type="text/css" />
      </head>
      <body>
        <div align="center">
          <h1>My Dictionary</h1>
        </div>
        <table border="1" 
            cellpadding="3" 
            cellspacing="0">
        <tr>
          <th>Word</th>
          <th>Definition</th>
        </tr>
        <xsl:for-each select="//Words/Word">
          <tr>
            <td>
              <xsl:value-of select="Value"/>
            </td>
            <td>
              <xsl:value-of select="Definition"/>
            </td>
          </tr>
        </xsl:for-each>
      </table>
    </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

The only other thing we need to do now is add the stylesheet reference. To do this, we add one line near the top of the file.

<?xml-stylesheet type='text/xsl' href='Dictionary.xslt'?>

Here is what the XML document would look like with this reference:

<?xml version="1.0"?>
<?xml-stylesheet type='text/xsl' href='Dictionary.xslt'?>
<Dictionary 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Words>
    <Word>
      <Value>House</Value>
      <Definition>A place where people live
             which provides shelter</Definition>
    </Word>
    <Word>
      <Value>Car</Value>
      <Definition>A device to transport people</Definition>
    </Word>
    <Word>
      <Value>Wood</Value>
      <Definition>Part of a tree</Definition>
    </Word>
    <Word>
      <Value>Serializer</Value>
      <Definition>An object for transforming another object
          to or from a linear sequence of bytes</Definition>
    </Word>
  </Words>
</Dictionary>

The problem is that when you use .NET's XmlSerializer.Serialize method to write out the object in XML format (see above), it doesn't normally write any stylesheet references (AKA processing directives). The trick is to first get the XML data into an XmlDocument and then to attach the processing instructions. Here is the code to do this:

private void SerializeWithStylesheet(Dictionary 
        dictionary, Stream stream, string stylesheet)
{
    // First serialize the document to an in-memory stream
    MemoryStream memXmlStream = new MemoryStream();

    XmlSerializer serializer = 
        new XmlSerializer(typeof(Dictionary));

    serializer.Serialize( memXmlStream, dictionary );

    // Now create a document with
    // the stylesheet processing instruction
    XmlDocument xmlDoc = new XmlDocument();

    // Now load the in-memory stream
    // XML data into the XMl document
    memXmlStream.Seek(0, SeekOrigin.Begin);
    xmlDoc.Load(memXmlStream);

    // Now add the stylesheet processing
    // instruction to the XML document
    XmlProcessingInstruction newPI;
    String PItext = string.Format("type='text/xsl' href='{0}'", stylesheet);
    newPI = xmlDoc.CreateProcessingInstruction("xml-stylesheet", PItext);

    xmlDoc.InsertAfter(newPI, xmlDoc.FirstChild);

    // Now write the document
    // out to the final output stream
    XmlTextWriter xmlWriter = new XmlTextWriter(stream, 
                              System.Text.Encoding.ASCII);
    xmlDoc.WriteTo(xmlWriter);
    xmlWriter.Flush();
}

Unfortunately, this involves serializing the object to a stream, deserializing it into a XmlDocument, and then reserializing it after first attaching the processing directive. It isn't the most efficient way to do this, but it's the simplest approach that I've found so far. An alternative would be to write your own serializer. Writing your own isn't that difficult, but it is definitely harder than this, and must also be revised every time you revise your objects.

Using the code

To do this for one of your own objects, you just have to do the following:

  1. Take the necessary steps to serialize your class using the XmlSerializer class. Mostly, this just involves adding the [Serializable] attribute as you see above.
  2. Create an XML stylesheet.
  3. Take the above SerializeWithStylesheet function and modify it to suit your own needs.

Points of Interest

In spite of their complexity, I am a big fan of stylesheets. They allow me to take out the functionality that was previously embedded into my application, and instead put it into a configuration file that the user can modify.

Links of Interest

History

  • 4/24/2006
    • First release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

cmumford
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
General:) Thanks! Pinmemberf.vanvugt22-Aug-06 22:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 25 Apr 2006
Article Copyright 2006 by cmumford
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid