![]() |
Languages »
XML »
Serializing
Intermediate
Serializing XML with stylesheetBy cmumfordAn explanation of how to serialize an object and include an XML-stylesheet processing instruction. |
C#, XML, Windows, .NET 2.0VS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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..
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:

In order to write out a stylesheet reference, we need to do two things:
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.
To do this for one of your own objects, you just have to do the following:
XmlSerializer class. Mostly, this just involves adding the [Serializable] attribute as you see above.
SerializeWithStylesheet function and modify it to suit your own needs. 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.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 25 Apr 2006 Editor: Smitha Vijayan |
Copyright 2006 by cmumford Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |