23

I am using this code to Serialize XML to String:

XmlWriterSettings xmlWriterSettings = new XmlWriterSettings
{
    indent = true,
    Encoding = Encoding.UTF8
};

using (var sw = new StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(sw, xmlWriterSettings))
    {
        XmlSerializer xmlSerializer = new XmlSerializer(moviesObject.GetType(), new XmlRootAttribute("category"));
        xmlSerializer.Serialize(xmlWriter, moviesObject);
    }
    return sw.ToString();
}

The problem is that i get :

<?xml version="1.0" encoding="utf-16"?>
<category xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" havemore="no">
  <items>
    <movie>
      <videoid>videoid1</videoid>
      <title>title1</title>
    </movie>
  </items>
</category>

There is any way to change the <?xml version="1.0" encoding="utf-16"?> to <?xml version="1.0" encoding="utf-8"?> ?

YosiFZ
  • 7,792
  • 21
  • 114
  • 221

3 Answers3

23

Here is a code with encoding as parameter. Please read the comments why there is a SuppressMessage for code analysis.

/// <summary>
/// Serialize an object into an XML string
/// </summary>
/// <typeparam name="T">Type of object to serialize.</typeparam>
/// <param name="obj">Object to serialize.</param>
/// <param name="enc">Encoding of the serialized output.</param>
/// <returns>Serialized (xml) object.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
internal static String SerializeObject<T>(T obj, Encoding enc)
{
    using (MemoryStream ms = new MemoryStream())
    {
        XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings()
        {
            // If set to true XmlWriter would close MemoryStream automatically and using would then do double dispose
            // Code analysis does not understand that. That's why there is a suppress message.
            CloseOutput = false, 
            Encoding = enc,
            OmitXmlDeclaration = false,
            Indent = true
        };
        using (System.Xml.XmlWriter xw = System.Xml.XmlWriter.Create(ms, xmlWriterSettings))
        {
            XmlSerializer s = new XmlSerializer(typeof(T));
            s.Serialize(xw, obj);
        }

        return enc.GetString(ms.ToArray());
    }
}
pepo
  • 8,644
  • 2
  • 27
  • 42
  • 3
    What about your answer solves the issue where setting `XmlWriterSettings` property for `Encoding` doesn't seem to propagate to the final output? I have set the `Encoding` property of `XmlWriterSettings` to `Encoding.UTF8` and passed this `XmlWriterSettings` to `XmlWriter.Create`, but it still serializes as `utf-16`. Same issue the OP has. I don't see anything in your code that would change that. What is the missing piece? – crush Oct 28 '15 at 18:43
  • 4
    I found my answer here: http://stackoverflow.com/a/4928759/1195273. I was using a `StringBuilder` instead of a `MemoryStream`. Using `StringBuilder` ignores the `Encoding` setting. Talk about hidden complexity - sheesh! – crush Oct 28 '15 at 18:44
  • 2
    @crush I'm glad you found the missing piece :) and that it has worked for you. – pepo Oct 28 '15 at 19:52
4

Try this

public static void SerializeXMLData(string pth, object xmlobj)
    {
        XmlSerializer serializer = new XmlSerializer(xmlobj.GetType());
        using (XmlTextWriter tw = new XmlTextWriter(pth, Encoding.UTF8))
        {
            tw.Formatting = Formatting.Indented;
            serializer.Serialize(tw, xmlobj);
        }
    }
bmi
  • 652
  • 2
  • 10
  • 17
2

The solution is simple:
Use a class of StringWriter that derives from StringWriter, and set the encoding in the constructor, and overwrite the Encoding property of the base class:

public sealed class StringWriterWithEncoding : System.IO.StringWriter
{
    private readonly System.Text.Encoding encoding;

    public StringWriterWithEncoding(System.Text.StringBuilder sb) : base(sb)
    {
        this.encoding = System.Text.Encoding.Unicode;
    }


    public StringWriterWithEncoding(System.Text.Encoding encoding)
    {
        this.encoding = encoding;
    }

    public StringWriterWithEncoding(System.Text.StringBuilder sb, System.Text.Encoding encoding) : base(sb)
    {
        this.encoding = encoding;
    }

    public override System.Text.Encoding Encoding
    {
        get { return encoding; }
    }
}

Then just pass an instance of StringWriterWithEnccoding to your method:

public static string SerializeToXml<T>(T ThisTypeInstance)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    string strReturnValue = null;

    //SerializeToXml<T>(ThisTypeInstance, new System.IO.StringWriter(sb));
    SerializeToXml<T>(ThisTypeInstance, new StringWriterWithEncoding(sb, System.Text.Encoding.UTF8));

    strReturnValue = sb.ToString();
    sb = null;

    return strReturnValue;
} // End Function SerializeToXml
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442