Serialize(TextWriter, Object) vs Serialize(XmlWriter, Object) - c#

The XmlSerializer.Serialize Method has overloads that accept TextWriter and XmlWriter.
My question is what are the practical differences between these two overloads in the follow examples? (list is a List<MyObjectModel>)
Example 1 (with TextWriter):
XmlSerializer serializer = new XmlSerializer(typeof(MyObjectModel));
using (TextWriter writer = new StreamWriter(savePath))
{
serializer.Serialize(writer, list);
}
Example 2 (with XmlWriter):
XmlSerializer serializer = new XmlSerializer(typeof(MyObjectModel));
using (XmlWriter writer = XmlWriter.Create(savePath))
{
serializer.Serialize(writer, list);
}
So far I've noticed that:
1) TextWriter seems to automatically perform indenting for you.
2) The default encoding for both is UTF-8.

I found the difference in the source code reference:
public void Serialize(TextWriter textWriter, object o, XmlSerializerNamespaces namespaces) {
XmlTextWriter xmlWriter = new XmlTextWriter(textWriter);
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.Indentation = 2;
Serialize(xmlWriter, o, namespaces);
}
In short, the TextWriter overload uses a XmlTextWriter underneath the hood and sets the formatting for you.

Related

How to control the encoding while serializing and deserializing?

I'm using serialization to a string as follows.
public static string Stringify(this Process self)
{
XmlSerializer serializer = new XmlSerializer(typeof(Process));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, self,);
return writer.ToString();
}
}
Then, I deserialize using this code. Please note that it's not an actual stringification from above that's used. In our business logic, it makes more sense to serialize a path, hence reading in from said path and creating an object based on the read data.
public static Process Processify(this string self)
{
XmlSerializer serializer = new XmlSerializer(typeof(Process));
using (XmlReader reader = XmlReader.Create(self))
return serializer.Deserialize(reader) as Process;
}
}
This works as supposed to except for a small issue with encoding. The string XML that's produced, contains the addition encoding="utf-16" as an attribute on the base tag (the one that's about XML version, not the actual data).
When I read in, I get an exception because of mismatching encodings. As far I could see, there's no way to specify the encoding for serialization nor deserialization in any of the objects I'm using.
How can I do that?
For now, I'm using a very brute work-around by simply cutting of the excessive junk like so. It's Q&D and I want to remove it.
public static string Stringify(this Process self)
{
XmlSerializer serializer = new XmlSerializer(typeof(Process));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, self,);
return writer.ToString().Replace(" encoding=\"utf-16\"", "");
}
}

XMLSerializer to XElement

I have been working with XML in database LINQ and find that it is very difficult to work with the serializer.
The database LINQ required a field that store XElement.
I have a complex object with many customized structure class, so I would like to use the XmlSerializer to serialize the object.
However, the serializer can only serialize to file ("C:\xxx\xxx.xml") or a memory stream.
However to convert or serialize it to be a XElement so that I can store in the database using LINQ?
And How to do the reverse? i.e. Deserialize an XElement...
Try to use this
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, value);
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
XElement element = XElement.Load(reader);
}
}
deserialize :
XmlSerializer xs = new XmlSerializer(typeof(XElement));
using (MemoryStream ms = new MemoryStream())
{
xs.Serialize(ms, xml);
ms.Position = 0;
xs = new XmlSerializer(typeof(YourType));
object obj = xs.Deserialize(ms);
}
To make what John Saunders was describing more explicit, deserialization is very straightforward:
public static object DeserializeFromXElement(XElement element, Type t)
{
using (XmlReader reader = element.CreateReader())
{
XmlSerializer serializer = new XmlSerializer(t);
return serializer.Deserialize(reader);
}
}
Serialization is a little messier because calling CreateWriter() from an XElement or XDocument creates child elements. (In addition, the XmlWriter created from an XElement has ConformanceLevel.Fragment, which causes XmlSerialize to fail unless you use the workaround here.) As a result, I use an XDocument, since this requires a single element, and gets us around the XmlWriter issue:
public static XElement SerializeToXElement(object o)
{
var doc = new XDocument();
using (XmlWriter writer = doc.CreateWriter())
{
XmlSerializer serializer = new XmlSerializer(o.GetType());
serializer.Serialize(writer, o);
}
return doc.Root;
}
First of all, see Serialize Method to see that the serializer can handle alot more than just memory streams or files.
Second, try using XElement.CreateWriter and then passing the resulting XmlWriter to the serializer.
The SQL has XML data type may be this can help you look at msdn

C# de-serialise Xml to object and serialise back to Xml again

I would like to use JsonFx to convert XML to/from custom types and LINQ queries. Can anyone please provide an example to de-serialisation and serialisation back again?
Here's an example of the XML I'm working with.
XML pasted here: http://pastebin.com/wURiaJM2
JsonFx Supports several strategies of binding json to .net objects including dynamic objects. https://github.com/jsonfx/jsonfx
Kind regards
Si
PS I did try pasting the xml document into StackOverflow but it removed a lot of the documents quotes and XML declaration.
Here's a method that I have used. It may require some tweaking:
public static string SerializeObject<T>(T item, string rootName, Encoding encoding)
{
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
writerSettings.Indent = true;
writerSettings.NewLineHandling = NewLineHandling.Entitize;
writerSettings.IndentChars = " ";
writerSettings.Encoding = encoding;
StringWriter stringWriter = new StringWriter();
using (XmlWriter xml = XmlWriter.Create(stringWriter, writerSettings))
{
XmlAttributeOverrides aor = null;
if (rootName != null)
{
XmlAttributes att = new XmlAttributes();
att.XmlRoot = new XmlRootAttribute(rootName);
aor = new XmlAttributeOverrides();
aor.Add(typeof(T), att);
}
XmlSerializer xs = new XmlSerializer(typeof(T), aor);
XmlSerializerNamespaces xNs = new XmlSerializerNamespaces();
xNs.Add("", "");
xs.Serialize(xml, item, xNs);
}
return stringWriter.ToString();
}
And for Deserialization:
public static T DeserializeObject<T>(string xml)
{
using (StringReader rdr = new StringReader(xml))
{
return (T)new XmlSerializer(typeof(T)).Deserialize(rdr);
}
}
And call it like this:
string xmlString = Serialization.SerializeObject(instance, "Root", Encoding.UTF8);
ObjectType obj = Serialization.DeserializeObject<ObjectType>(xmlString);
Hope this helps. The rootName parameter in the Serialize method lets you customize the value of the root node in the resulting xml string. Also, your classes must be decorated with the proper Xml attributes which will control how an entity is serialized.
This post explains how to create an XSD and a Classes from an XML file and then covers serialisation and de-serialisation.
http://geekswithblogs.net/CWeeks/archive/2008/03/11/120465.aspx
Using this technique with the XSD.exe to create an XSD and then classes in a CS file I was able to serialisation and then de-serialisation back again.
However the serialisation process does not create an exact representation of the source XML, so there's still some post work to be done there.

XmlSerializer Converts newlines

I'm trying to serialize an object to memory, pass it to another process as a string, and deserialize it.
I've discovered that the XML Serialization process strips the \r off of the newlines for strings in the object.
byte[] b;
// serialize to memory.
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xml = new XmlSerializer(this.GetType());
xml.Serialize(ms, this);
b = ms.GetBuffer();
}
// I can now send the bytes to my process.
Process(b);
// On the other end, I use:
using (MemoryStream ms = new MemoryStream(b))
{
XmlSerializer xml = new XmlSerializer(this.GetType());
clone = (myObject)xml.Deserialize(ms);
}
How do I serialize an object without serializing it to disk just like this, but without mangling the newlines in the strings?
The strings should be wrapped in CDATA sections to preserve the newlines.
The answer came from anther SO post, but I'm reposting it here because I had to tweak it a little.
I had to create a new class to manage XML read/write to memory stream. Here it is:
public class SafeXmlSerializer : XmlSerializer
{
public SafeXmlSerializer(Type type) : base(type) { }
public new void Serialize(StreamWriter stream, object o)
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.NewLineHandling = NewLineHandling.Entitize;
using (XmlWriter xmlWriter = XmlWriter.Create(stream, ws))
{
base.Serialize(xmlWriter, o);
}
}
}
Since it is built on top of XmlSerializer, it should behave exactly as expected. It's just that when I serialize with a StreamWriter, I will use the "safe" version of the serialization, thus saving myself the headache.
I hope this helps someone else.

Omitting XML processing instruction when serializing an object

I'm serializing an object in a C# VS2003 / .Net 1.1 application. I need it serialized without the processing instruction, however. The XmlSerializer class puts out something like this:
<?xml version="1.0" encoding="utf-16" ?>
<MyObject>
<Property1>Data</Property1>
<Property2>More Data</Property2>
</MyObject>
Is there any way to get something like the following, without processing the resulting text to remove the tag?
<MyObject>
<Property1>Data</Property1>
<Property2>More Data</Property2>
</MyObject>
For those that are curious, my code looks like this...
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
StringBuilder builder = new StringBuilder();
using ( TextWriter stringWriter = new StringWriter(builder) )
{
serializer.Serialize(stringWriter, comments);
return builder.ToString();
}
I made a small correction
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using ( XmlWriter stringWriter = XmlWriter.Create(builder, settings) )
{
serializer.Serialize(stringWriter, comments);
return builder.ToString();
}
In 2.0, you would use XmLWriterSettings.OmitXmlDeclaration, and serialize to an XmlWriter - however I don't think this exists in 1.1; so not entirely useful - but just one more "consider upgrading" thing... and yes, I realise it isn't always possible.
The following link will take you to a post where someone has a method of supressing the processing instruction by using an XmlWriter and getting into an 'Element' state rather than a 'Start' state. This causes the processing instruction to not be written.
Suppress Processing Instruction
If you pass an XmlWriter to the serializer, it will only emit a processing
instruction if the XmlWriter's state is 'Start' (i.e., has not had anything
written to it yet).
// Assume we have a type named 'MyType' and a variable of this type named
'myObject'
System.Text.StringBuilder output = new System.Text.StringBuilder();
System.IO.StringWriter internalWriter = new System.IO.StringWriter(output);
System.Xml.XmlWriter writer = new System.Xml.XmlTextWriter(internalWriter);
System.Xml.Serialization.XmlSerializer serializer = new
System.Xml.Serialization.XmlSerializer(typeof(MyType));
writer.WriteStartElement("MyContainingElement");
serializer.Serialize(writer, myObject);
writer.WriteEndElement();
In this case, the writer will be in a state of 'Element' (inside an element)
so no processing instruction will be written. One you finish writing the
XML, you can extract the text from the underlying stream and process it to
your heart's content.
What about omitting namespaces ?
instead of using
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");
ex:
<message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
If by "processing instruction" you mean the xml declaration, then you can avoid this by setting the OmitXmlDeclaration property of XmlWriterSettings. You'll need to serialize using an XmlWriter, to accomplish this.
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using ( XmlWriter stringWriter = new StringWriter(builder, settings) )
{
serializer.Serialize(stringWriter, comments);
return builder.ToString();
}
But ah, this doesn't answer your question for 1.1. Well, for reference to others.
This works in .NET 1.1. (But you should still consider upgrading)
XmlSerializer s1= new XmlSerializer(typeof(MyClass));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add( "", "" );
MyClass c= new MyClass();
c.PropertyFromDerivedClass= "Hallo";
sw = new System.IO.StringWriter();
s1.Serialize(new XTWND(sw), c, ns);
....
/// XmlTextWriterFormattedNoDeclaration
/// helper class : eliminates the XML Documentation at the
/// start of a XML doc.
/// XTWFND = XmlTextWriterFormattedNoDeclaration
public class XTWFND : System.Xml.XmlTextWriter
{
public XTWFND(System.IO.TextWriter w) : base(w) { Formatting = System.Xml.Formatting.Indented; }
public override void WriteStartDocument() { }
}

Categories