XML序列化期间将忽略属性XmlNamespaceDeclarations

Wal*_*mar 3 c# xml serialization xml-namespaces

我尝试使用自定义命名空间序列化对象.这就是这个类的样子:

[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;
}
Run Code Online (Sandbox Code Playgroud)

以下是序列化它的代码:

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
serializer.Serialize(xmlWriter, obj);
Run Code Online (Sandbox Code Playgroud)

预期的结果是

<Root xmlns="myNamespace" />
Run Code Online (Sandbox Code Playgroud)

但是它仍然有xmlns:xsi和xmlns:xsd属性:

<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="myNamespace" />
Run Code Online (Sandbox Code Playgroud)

当我序列化使用时serializer.Serialize(xmlWriter, obj, obj.Xmlns),结果是正确的.

为什么序列化程序会忽略该XmlNamespaceDeclarations属性?它不应该自动从它获取命名空间声明吗?如何在序列化类中定义名称空间?

提前致谢!

Ian*_*Ian 5

为什么序列化程序会忽略XmlNamespaceDeclarations属性?它不应该自动从它获取命名空间声明吗?

实际上,Serializer它的作用并不是 忽略你的,XmlNamespaceDeclarations而是它们添加到默认的内部,XmlWriter namespaces.

默认情况下,已经有一些prefixes-namespaces pairs(或者我只是简单地称为namespaces这个答案的休息简单)嵌入到XmlWriter.他们是你看到的:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" //note the lovely pairs here
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
Run Code Online (Sandbox Code Playgroud)

因此,如果你使用XmlWriter,你必须忍受它default namespaces,不幸的是不暴露给外部用户.而且,为了让事情"变得更糟"(实际上,情况并非如此糟糕,但我试图将其置于上下文中),它不知何故不允许你对它做任何事情.

唯一XmlWriter与之有关的属性namespaceNamespaceHandling,它只能设置为删除重复 namespaces或保留它们.这意味着,如果您以某种方式(相当神奇地)duplicate namespaces为您声明的属性,该属性将只有任何用途serializable class:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
Run Code Online (Sandbox Code Playgroud)

尽管如此,XmlWriter仍然有一些"好"的东西你可以XmlDeclaration通过设置省略:

OmitXmlDeclaration = true;
Run Code Online (Sandbox Code Playgroud)

当您创建XmlWriterSettings并使用设置初始化您的XmlWriter

简而言之,我们不能希望XmlWriter通过删除它来为我们做好事default namespaces- 它根本不可能.

因此,我们必须Serializer得到解决方案


如何在序列化类中定义名称空间?

信不信由你,它就像你已经做过的一样!

重载方法序列化(XmlWriter的,对象,XmlSerializerNamespaces)只是用于该目的而设计的.当你打电话时:

serializer.Serialize(xmlWriter, obj, obj.Xmlns);
Run Code Online (Sandbox Code Playgroud)

取代default namespaces + your namespaces your namespaces

如果你使用Serialize(XmlWriter,?Object)过载,有什么Serializer做的是采取一切namespacesXmlWriter,以及在Object然后写XML文件.因此,你得到了所有namespaces:默认和你的.

这可能是因为XmlWriter(内部)将XmlNamespaceScope应用于XmlNamespaceScope.All您 - 再次 - 对此无能为力.

但是当你使用时Serialize(XmlWriter,?Object,?XmlSerializerNamespaces),你实际上告诉你Serializer只使用XmlSerializerNamespaces你指定的.所以,它做对了!

换句话说,您所做的就是获取文件中所需命名空间的"官方"方式Xml.

除此之外,您还可以根据需要将多个数据放入namespacesXML文件中,只需使用多次即可Xmlns.Add(prefix, ns).

因此,您已经为您的目的做了正确的事情.我只想解释为什么会这样.