21

I have a couple extension methods that handle serialization of my classes, and since it can be a time consuming process, they are created once per class, and handed out by this method.

public static XmlSerializer GetSerializerFor(Type typeOfT)
{
    if (!serializers.ContainsKey(typeOfT))
    {
        var xmlAttributes = new XmlAttributes();
        var xmlAttributeOverrides = new XmlAttributeOverrides();

        System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));

        xmlAttributes.Xmlns = false;
        xmlAttributeOverrides.Add(typeOfT, xmlAttributes);

        var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
        serializers.Add(typeOfT, newSerializer);
    }

    return serializers[typeOfT];
}

This is called by the extension method .Serialize()

public static XElement Serialize(this object source)
{
    try
    {
        var serializer = XmlSerializerFactory.GetSerializerFor(source.GetType());
        var xdoc = new XDocument();
        using (var writer = xdoc.CreateWriter())
        {
            serializer.Serialize(writer, source, new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") }));
        }

        return (xdoc.Document != null) ? xdoc.Document.Root : new XElement("Error", "Document Missing");
    }
    catch (Exception x)
    {
        return new XElement("Error", x.ToString());
    }
}

Unfortunately, when Serializing classes that are auto-generated, they have the attribute XmlTypeAttribute(Namespace="http://tempuri.org/") applied to them.

This causes the deserialization by the the non-auto-generated counterparts to fail.

I need the serializer to completely ignore and not apply the namespace, but what I have written in the first block of code doesn't seem to remove it, I still end up with xml like this

<Note>
  <ID xmlns="http://tempuri.org/">12</ID>
  <Author xmlns="http://tempuri.org/">
    <ID>1234</ID>
    <Type>Associate</Type>
    <IsAvailable>false</IsAvailable>
  </Author>
  <Created xmlns="http://tempuri.org/">2010-06-22T09:38:01.5024351-05:00</Created>
  <Text xmlns="http://tempuri.org/">This is an update</Text>
</Note>

Instead of the same, minus the xmlns="http://tempuri.org/" attribute.

Please help, thanks, this is driving me crazy!

EDIT:

I know the problem, just not how to fix it.

My class, isn't just full of simple types.

It contains properties with types of other classes. Which are also auto-generated with the XmlTypeAttribute(Namespace = "http://tempuri.org/") attribute. So what is happening, is that when serialization occurs, and it serializes the properties of my class, they aren't going through my custom serialization, and thus, are having the attribute applied and not overridden.

Now I just need to figure out how to jump that hoop. Any thoughts as to how?

EDIT 2:

The following works to serialize WITHOUT xmlns... but I'm having a problem on the deserialization end, just not yet sure if it's related or not

public static XmlSerializer GetSerializerFor(Type typeOfT)
{
    if (!serializers.ContainsKey(typeOfT))
    {
        var xmlAttributes = new XmlAttributes();
        var xmlAttributeOverrides = new XmlAttributeOverrides();

        System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));

        xmlAttributes.XmlType = new XmlTypeAttribute
        {
            Namespace = ""
        };

        xmlAttributes.Xmlns = false;

        var types = new List<Type> {typeOfT, typeOfT.BaseType};

        foreach (var property in typeOfT.GetProperties())
        {
            types.Add(property.PropertyType);
        }

        types.RemoveAll(t => t.ToString().StartsWith("System."));

        foreach (var type in types)
        {
            xmlAttributeOverrides.Add(type, xmlAttributes);
        }

        var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
        //var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, extraTypes.ToArray(), new XmlRootAttribute(), string.Empty);
        //var newSerializer = new XmlSerializer(typeOfT, string.Empty);

        serializers.Add(typeOfT, newSerializer);
    }

    return serializers[typeOfT];
}

EDIT3: Ended up using solution from How to remove all namespaces from XML with C#?

public static XElement RemoveAllNamespaces(this XElement source)
{
    return !source.HasElements
               ? new XElement(source.Name.LocalName)
                     {
                         Value = source.Value
                     }
               : new XElement(source.Name.LocalName, source.Elements().Select(el => RemoveAllNamespaces(el)));
}
Community
  • 1
  • 1
CaffGeek
  • 21,856
  • 17
  • 100
  • 184

5 Answers5

60

A working solution, for the record!

var ns = new XmlSerializerNamespaces();
ns.Add("", ""); 
var serializer = new XmlSerializer(yourType); 
serializer.Serialize(xmlTextWriter, someObject, ns);
VahidN
  • 18,457
  • 8
  • 73
  • 117
  • 1
    Certainly a better solution. Works like a charm! – Engineer007 May 15 '13 at 19:11
  • 14
    For the record, this will remove the `xsi` and `xsd`, but it will ADD a new `xmlns:prefix=` and add the prefix to all your tags if you have `XmlTypeAttribute`s with namespaces specified in your classes. – redtetrahedron May 31 '13 at 16:25
  • 1
    This really worked perfect for me, after trying so many different things that just didn't do the job without side effects. Thank you so much. – JoeFox Sep 20 '13 at 12:54
  • 2
    Gotta say, nay. I get `xmlns=""` on every element. – JMD Feb 19 '17 at 21:34
  • works with .NET Core. using System.Xml; using System.Xml.Serialization; – Sergei G Oct 22 '20 at 17:33
5

No problem - just pass an empty string as the default namespace to the XML serializer:

XmlSerializer newSerializer = 
   new XmlSerializer(typeOfT, "");

Unfortunately, there's no easy constructor overload if you really need to define the XmlAttributeOverrides and the default namespace - so either you can skip the XmlAttributeOverrides and use that constructor I mentioned, or you need to use the one that defines all possible parameters (including XmlAttributeOverrides and default XML namespaces - and a few more).

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • that's what I had before actually, it didn't work, it was still using the value from the XmlTypeAttribute on the class. And I just tried the following and it didn't work either `var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, new Type[]{}, new XmlRootAttribute(), "");` – CaffGeek Jun 22 '10 at 15:26
  • I know the problem...just not the solution. See the edit I made to the original question. – CaffGeek Jun 22 '10 at 15:45
  • 5
    did not worked. Not actually the answer. Answer from VihidN works for me! – Irfan Sep 12 '13 at 12:06
1
 public static byte[] SerializeByteByType(object objectToSerialize, Type type)
    {
        XmlWriterSettings xmlSetting = new XmlWriterSettings()
        {
            NewLineOnAttributes = false,
            OmitXmlDeclaration = true,
            Indent = false,
            NewLineHandling = NewLineHandling.None,
            Encoding = Encoding.UTF8,
            NamespaceHandling = NamespaceHandling.OmitDuplicates
        };

        using (MemoryStream stm = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(stm, xmlSetting))
            {
                var xmlAttributes = new XmlAttributes();
                var xmlAttributeOverrides = new XmlAttributeOverrides();

                xmlAttributes.Xmlns = false;
                xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };
                xmlAttributeOverrides.Add(type, xmlAttributes);

                XmlSerializer serializer = new XmlSerializer(type, xmlAttributeOverrides);
                //Use the following to serialize without namespaces
                XmlSerializerNamespaces xmlSrzNamespace = new XmlSerializerNamespaces();
                xmlSrzNamespace.Add("", "");

                serializer.Serialize(writer, objectToSerialize, xmlSrzNamespace);
                stm.Flush();
                stm.Position = 0;
            }

            return stm.ToArray();
        }
    }         
  • 1
    Instead "xmlAttributeOverrides.Add(type, xmlAttributes);" must be: "var types = type.Assembly.GetTypes().Where( t => string.Equals( t.Namespace, currentType.Namespace, StringComparison.Ordinal ) ); var xmlAttributeOverrides = new XmlAttributeOverrides(); foreach ( var t in types ) xmlAttributeOverrides.Add( t, xmlAttributes );" – Mentor Mar 29 '17 at 14:45
1

Working solution (without empty xmlns attribute):

var ns = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
XmlSerializer serializer = new XmlSerializer(typeof(XmlInfo));
XmlDocument doc = new XmlDocument();
using (var ms = new MemoryStream()) {
    serializer.Serialize(ms, this, ns);
    ms.Position = 0;
    doc.Load(ms);
}
Adam Silenko
  • 3,025
  • 1
  • 14
  • 30
0
    public static string SerializeToXml(object obj)
    {
        UTF8Encoding encoding = new UTF8Encoding(false);

        var xmlAttributes = new XmlAttributes();
        xmlAttributes.Xmlns = false;
        xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };

        var xmlAttributeOverrides = new XmlAttributeOverrides();

        var types = obj.GetType().Assembly.GetTypes().Where(t => string.Equals(t.Namespace, obj.GetType().Namespace, StringComparison.Ordinal));
        foreach (var t in types) xmlAttributeOverrides.Add(t, xmlAttributes);

        XmlSerializer sr = new XmlSerializer(obj.GetType(), xmlAttributeOverrides);

        MemoryStream memoryStream = new MemoryStream();
        StreamWriter writer = new StreamWriter(memoryStream, encoding);

        XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
        namespaces.Add(string.Empty, string.Empty);

        // get the stream from the writer
        memoryStream = writer.BaseStream as MemoryStream;

        sr.Serialize(writer, obj, namespaces);

        // apply encoding to the stream 
        return (encoding.GetString(memoryStream.ToArray()).Trim());
    }

It will even work for complex object containing nested object Credits to user3444796 and Mentor