Asked  7 Months ago    Answers:  5   Viewed   39 times

I have a C# class that I have inherited. I have successfully "built" the object. But I need to serialize the object to XML. Is there an easy way to do it?

It looks like the class has been set up for serialization, but I'm not sure how to get the XML representation. My class definition looks like this:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.domain.com/test")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.domain.com/test", IsNullable = false)]
public partial class MyObject
{
  ...
}

Here is what I thought I could do, but it doesn't work:

MyObject o = new MyObject();
// Set o properties
string xml = o.ToString();

How do I get the XML representation of this object?

 Answers

57

You have to use XmlSerializer for XML serialization. Below is a sample snippet.

 XmlSerializer xsSubmit = new XmlSerializer(typeof(MyObject));
 var subReq = new MyObject();
 var xml = "";

 using(var sww = new StringWriter())
 {
     using(XmlWriter writer = XmlWriter.Create(sww))
     {
         xsSubmit.Serialize(writer, subReq);
         xml = sww.ToString(); // Your XML
     }
 }
Tuesday, June 1, 2021
 
IvanH
answered 7 Months ago
10

Use a StringWriter instead of a StreamWriter:

public static string SerializeObject<T>(this T toSerialize)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

    using(StringWriter textWriter = new StringWriter())
    {
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }
}

Note, it is important to use toSerialize.GetType() instead of typeof(T) in XmlSerializer constructor: if you use the first one the code covers all possible subclasses of T (which are valid for the method), while using the latter one will fail when passing a type derived from T.    Here is a link with some example code that motivate this statement, with XmlSerializer throwing an Exception when typeof(T) is used, because you pass an instance of a derived type to a method that calls SerializeObject that is defined in the derived type's base class: http://ideone.com/1Z5J1.

Also, Ideone uses Mono to execute code; the actual Exception you would get using the Microsoft .NET runtime has a different Message than the one shown on Ideone, but it fails just the same.

Tuesday, June 8, 2021
 
kwhohasamullet
answered 6 Months ago
44

You can use these two extension methods to serialize and deserialize between XElement and your objects.

public static XElement ToXElement<T>(this object obj)
{
    using (var memoryStream = new MemoryStream())
    {
        using (TextWriter streamWriter = new StreamWriter(memoryStream))
        {
            var xmlSerializer = new XmlSerializer(typeof(T));
            xmlSerializer.Serialize(streamWriter, obj);
            return XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray()));
        }
    }
}

public static T FromXElement<T>(this XElement xElement)
{
        var xmlSerializer = new XmlSerializer(typeof(T));
        return (T)xmlSerializer.Deserialize(xElement.CreateReader());
}

USAGE

XElement element = myClass.ToXElement<MyClass>();
var newMyClass = element.FromXElement<MyClass>();
Monday, June 28, 2021
 
Owen
answered 6 Months ago
25

1.

You can set XmlWriterSettings's CheckCharacters property to avoid writing illegal chars.(Serialize method would throw exception)

using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    var writer = XmlWriter.Create(tmpFileStream, new XmlWriterSettings() { CheckCharacters = true});
    serializer.Serialize(writer, items);
}

2.

You can create your own XmlTextWriter to filter out unwanted chars while serializing

using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    var writer = new MyXmlWriter(tmpFileStream);
    serializer.Serialize(writer, items);
}

public class MyXmlWriter : XmlTextWriter
{
    public MyXmlWriter(Stream s) : base(s, Encoding.UTF8)
    {
    }

    public override void WriteString(string text)
    {
        string newText = String.Join("", text.Where(c => !char.IsControl(c)));
        base.WriteString(newText);
    }
}

3.

By creating your own XmlTextReader you can filter out unwanted chars while deserializing

using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
    var reader = new MyXmlReader(plainTextFile);
    result = (SomeObject)serializer.Deserialize(reader); 
}

public class MyXmlReader : XmlTextReader
{
    public MyXmlReader(Stream s) : base(s)
    {
    }

    public override string ReadString()
    {
        string text =  base.ReadString();
        string newText = String.Join("", text.Where(c => !char.IsControl(c)));
        return newText;
    }
}

4.

You can set XmlReaderSettings's CheckCharacters property to false. Deserialization will work now smoothly. (you'll get v back.)

using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
    var reader = XmlReader.Create(plainTextFile, new XmlReaderSettings() { CheckCharacters = false });
    result = (SomeObject)serializer.Deserialize(reader); 
}
Sunday, August 1, 2021
 
Benji
answered 4 Months ago
93

Without changing the type of Value I think it's not possible. You can add the attribute XmlElement(ElementName="Text") on Value but you will obtain a result similar to this:

<MyClass> 
    <Text>3</Text> 
</MyClass> 

Edited: Another solution can involve XSLT transformation: you can generate the xml using .Net serialization and after apply a xml transformation.

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

The trasformation of my example should be something like this:

<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="MyClass">
        <MyClass>
            <Text>
               <xsl:attribute name="Value">
                    <xsl:value-of select="Text"/>
               </xsl:attribute>
            </Text>
        </MyClass>
    </xsl:template>
</xsl:stylesheet>
Tuesday, November 9, 2021
 
user000001
answered 3 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share