Click here to Skip to main content
15,868,016 members
Articles / Programming Languages / XML
Article

Serializing XML with stylesheet

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
25 Apr 20063 min read 65K   423   26   7
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:

C#
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:

C#
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:

C#
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
<?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):

Image 1

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

Image 2

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
<?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
<?xml-stylesheet type='text/xsl' href='Dictionary.xslt'?>

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

XML
<?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:

C#
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


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralA Better way using xmlDocument in 2.0 Pin
Pranav Kaushik12-Nov-07 23:17
Pranav Kaushik12-Nov-07 23:17 
Questionplz help me Pin
aliCarryme22-Aug-07 0:33
aliCarryme22-Aug-07 0:33 
Hi
how can i serialize my object to xml without xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
in my root tag.

tanx

@liCarryMe
AnswerRe: plz help me Pin
Leslie Godwin27-Nov-08 20:03
Leslie Godwin27-Nov-08 20:03 
GeneralAnother Alternative Pin
thornleyxp@yahoo.com25-Jul-07 10:19
thornleyxp@yahoo.com25-Jul-07 10:19 
QuestionWhat about? Pin
Martin Lercher23-Nov-06 8:01
Martin Lercher23-Nov-06 8:01 
AnswerRe: What about? Pin
cmumford14-Feb-07 3:27
cmumford14-Feb-07 3:27 
General:) Thanks! Pin
f.vanvugt22-Aug-06 22:27
f.vanvugt22-Aug-06 22:27 

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

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