Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attribute XmlNamespaceDeclarations is ignored during XML serialization

I try to serialize an object with custom namespaces. This is how the class looks like:

[XmlRoot("Root", Namespace = "myNamespace")]
public partial class MyClass
{
    public MyClass()
    {
        this.Xmlns = new XmlSerializerNamespaces();
        this.Xmlns.Add(string.Empty, "myNamespace");
    }

    [XmlNamespaceDeclarations()]
    public XmlSerializerNamespaces Xmlns = null;
}

And here is the code to serialize it:

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
serializer.Serialize(xmlWriter, obj);

The expected result is

<Root xmlns="myNamespace" />

However it still has xmlns:xsi and xmlns:xsd attributes:

<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="myNamespace" />

When I serialize using serializer.Serialize(xmlWriter, obj, obj.Xmlns), the result is correct.

Why does serializer ignore that XmlNamespaceDeclarations attribute? Shouldn't it automatically take the namespace declarations from it? How can I define namespaces inside serialized class?

Thanks in advance!

like image 231
Waldemar Avatar asked Feb 15 '16 19:02

Waldemar


1 Answers

Why does serializer ignore that XmlNamespaceDeclarations attribute? Shouldn't it automatically take the namespace declarations from it?

Actually, what the Serializer does is not ignoring your XmlNamespaceDeclarations but adding them into the default, internal, XmlWriter namespaces.

By default, there are already some prefixes-namespaces pairs (or I would simply call namespaces for simplicity for the rests of this answer) embedded to the XmlWriter. They are what you see:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" //note the lovely pairs here
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 

Thus, if you use XmlWriter, you got to bear with its default namespaces which unfortunately are not exposed to the outside user. And, to make things "worse" (actually, not that worse, but I try to put this in context), it somehow does not allow you to do anything with it.

The only XmlWriter property that got something to do with namespace is NamespaceHandling, which can only be set to either removing duplicate namespaces or retaining them. Which means, the property would only be of any use if you have somehow - rather magically - declared duplicate namespaces for your serializable class:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 

Nevertheless, XmlWriter still have some "good" things that you can omit the XmlDeclaration by setting:

OmitXmlDeclaration = true;

when you create your XmlWriterSettings and use the settings to initialize your XmlWriter

In short, we cannot hope XmlWriter to do good things to us by removing its default namespaces - it simply can't.

And thus, we must to the Serializer to get the solution


How can I define namespaces inside serialized class?

Believe it or not, it is exactly like what you already did!

The overloading method Serialize(XmlWriter, Object, XmlSerializerNamespaces) is designed just for that purpose. When you call it:

serializer.Serialize(xmlWriter, obj, obj.Xmlns);

It replaces the default namespaces + your namespaces with only your namespaces

If you use Serialize(XmlWriter, Object) overload, what the Serializer does is to take all the namespaces in the XmlWriter as well as in the Object and then write XML file. Thus you got all the namespaces there: the default and yours.

This is probably because XmlWriter also (internally) apply XmlNamespaceScope to be XmlNamespaceScope.All which you - again - can do nothing about it.

But when you use Serialize(XmlWriter, Object, XmlSerializerNamespaces), you actually tell the Serializer to only use XmlSerializerNamespaces that you specify. And so, it does the right thing!

In other words, what you did is already an "official" way for getting the namespaces that you want in the Xml file.

That note aside, you could also put multiple namespaces to your XML file as you wish by simply using as many times Xmlns.Add(prefix, ns) as you want.

Thus, you already did the right thing for your purpose. I merely trying to explain why it is so.

like image 161
Ian Avatar answered Oct 17 '22 09:10

Ian