How to serialize an object to XML without getting xmlns="..."?
Asked Answered
D

6

125

Is there a way for me to serialize an object in .NET without the XML Namespaces automatically serializing also? It seems that by default .NET believes the XSI and XSD namespaces should be included, but I don't want them there.

Dreyer answered 3/11, 2008 at 15:17 Comment(0)
D
165

Ahh... nevermind. It's always the search after the question is posed that yields the answer. My object that is being serialized is obj and has already been defined. Adding an XMLSerializerNamespace with a single empty namespace to the collection does the trick.

In VB like this:

Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")

Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True

Using ms As New MemoryStream(), _
    sw As XmlWriter = XmlWriter.Create(ms, settings), _
    sr As New StreamReader(ms)
    xs.Serialize(sw, obj, ns)
    ms.Position = 0
    Console.WriteLine(sr.ReadToEnd())
End Using

in C# like this:

//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);
Dreyer answered 3/11, 2008 at 15:23 Comment(4)
I tried this in VB, the xsi and xsd attributes disappeared but attributes such as xmlns:q12=, d3p1:type, and xmlns:d3p1 appeared.Phillisphilly
I tried the C# version and it removed the xsi and xsd but added a prefix of q1: to all the XML tag names, which I did not want. It looks like the C# example is incomplete, referencing myXmlTextWriter which I assume needs to be initialized the same way as the VB example.Attic
@Attic Did you find a way to get rid of the q1 crap?Hued
Refer to the answer #31946740, if q1 added as blank namespaceKrall
O
22

If you want to get rid of the extra xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" and xmlns:xsd="http://www.w3.org/2001/XMLSchema", but still keep your own namespace xmlns="http://schemas.YourCompany.com/YourSchema/", you use the same code as above except for this simple change:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   
Outboard answered 12/2, 2010 at 1:19 Comment(0)
O
19

If you want to remove the namespace you may also want to remove the version, to save you searching I've added that functionality so the below code will do both.

I've also wrapped it in a generic method as I'm creating very large xml files which are too large to serialize in memory so I've broken my output file down and serialize it in smaller "chunks":

    public static string XmlSerialize<T>(T entity) where T : class
    {
        // removes version
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;

        XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            // removes namespace
            var xmlns = new XmlSerializerNamespaces();
            xmlns.Add(string.Empty, string.Empty);

            xsSubmit.Serialize(writer, entity, xmlns);
            return sw.ToString(); // Your XML
        }
    }
Ober answered 28/9, 2016 at 2:28 Comment(3)
Beware, StringWriter defaults to UTF-16 Encoding which can lead to deserialization issues downstream. using (var reader = XmlReader.Create(stream)){ reader.Read(); } This throws an exception because the declaration states it is UTF-16 while the content was actually written as UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'Laughable
To get around this and still use XmlReader, you can use var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true); The true will use the BOM if found, else the default you provide.Laughable
Change to: (this T entity) and now you have a sweet extension method.Viguerie
Y
10

I Suggest this helper class:

public static class Xml
{
    #region Fields

    private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
    private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});

    #endregion

    #region Methods

    public static string Serialize(object obj)
    {
        if (obj == null)
        {
            return null;
        }

        return DoSerialize(obj);
    }

    private static string DoSerialize(object obj)
    {
        using (var ms = new MemoryStream())
        using (var writer = XmlWriter.Create(ms, WriterSettings))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, Namespaces);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public static T Deserialize<T>(string data)
        where T : class
    {
        if (string.IsNullOrEmpty(data))
        {
            return null;
        }

        return DoDeserialize<T>(data);
    }

    private static T DoDeserialize<T>(string data) where T : class
    {
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
        {
            var serializer = new XmlSerializer(typeof (T));
            return (T) serializer.Deserialize(ms);
        }
    }

    #endregion
}

:)

Yarrow answered 19/2, 2015 at 12:43 Comment(2)
great answer :) i've also add this line stream.Position = 0; and returned the entire stream in my solution.. worked as expected - all deceleration tags were removedNumbat
Adding the namespaces argument to the serializer call alone worked for me to remove the default namespaces. Writing new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty}) instead of new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")}) is an intentionally clearer way to code it, in my opinion.Gass
N
7

If you are unable to get rid of extra xmlns attributes for each element, when serializing to xml from generated classes (e.g.: when xsd.exe was used), so you have something like:

<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />

then i would share with you what worked for me (a mix of previous answers and what i found here)

explicitly set all your different xmlns as follows:

Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
xmlns.Add("three",  "urn:names:specification:schema:xsd:three")

then pass it to the serialize

serializer.Serialize(writer, object, xmlns);

you will have the three namespaces declared in the root element and no more needed to be generated in the other elements which will be prefixed accordingly

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...
Nonesuch answered 11/7, 2014 at 20:25 Comment(0)
S
0
        XmlWriterSettings settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true
        };

        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");

        StringBuilder sb = new StringBuilder();

        XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            xs.Serialize(xw, model, ns);
            xw.Flush();
            return sb.ToString();
        }
Septavalent answered 21/11, 2019 at 16:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.