【问题标题】:Attribute XmlNamespaceDeclarations is ignored during XML serializationXML 序列化期间忽略属性 XmlNamespaceDeclarations
【发布时间】:2025-11-24 19:35:02
【问题描述】:

我尝试用自定义命名空间序列化一个对象。类是这样的:

[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;
}

这是序列化它的代码:

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

预期的结果是

<Root xmlns="myNamespace" />

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

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

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

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

提前致谢!

【问题讨论】:

    标签: c# xml serialization xml-namespaces


    【解决方案1】:

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

    实际上,Serializer 所做的是不是 忽略您的XmlNamespaceDeclarations,而是添加它们到默认的内部@987654327 @。

    默认情况下,XmlWriter 中已经嵌入了一些 prefixes-namespaces pairs(或者为了简单起见,我会简单地调用 namespaces)。它们就是你所看到的:

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

    因此,如果你使用XmlWriter,你必须忍受它的default namespaces,不幸的是它不会暴露给外部用户。而且,为了让事情“更糟”(实际上,并没有那么糟,但我试着把它放在上下文中),它不知何故不允许你用它做任何事情。

    唯一与namespace 相关的XmlWriter 属性是NamespaceHandling,它只能设置为删除重复 namespaces 或保留它们。这意味着,只有当您以某种方式(相当神奇地)为您的 serializable class 声明 duplicate namespaces 时,该属性才有用:

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

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

    OmitXmlDeclaration = true;
    

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

    简而言之,我们不能指望XmlWriter 通过删除它的default namespaces 来为我们做好事——它根本做不到。

    因此,我们必须向Serializer 获取解决方案


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

    信不信由你,它和你已经做过的一模一样

    overloading 方法 Serialize(XmlWriter, Object, XmlSerializerNamespaces) 就是为此目的而设计的。当你调用它时:

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

    替换 default namespaces + your namespaces 只有 your namespaces

    如果使用Serialize(XmlWriter, Object) 重载,Serializer 所做的是将XmlWriterObject 中的所有namespaces 取出,然后写入XML 文件。这样你就得到了所有的namespaces默认的和你的

    这可能是因为XmlWriter 也(在内部)将XmlNamespaceScope 应用为XmlNamespaceScope.All,而您又一次对此无能为力。

    但是当您使用Serialize(XmlWriter, Object, XmlSerializerNamespaces) 时,实际上是告诉Serializer 只使用您指定的XmlSerializerNamespaces。所以,它做了正确的事!

    换句话说,您所做的已经是在Xml 文件中获取所需命名空间的“官方”方式。

    除此之外,您还可以根据需要将多个 namespaces 放入您的 XML 文件,只需使用任意多次 Xmlns.Add(prefix, ns)

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

    【讨论】:

    • 好的,可以替换命名空间。那么如何从输出中删除命名空间呢?我不想要它们或不需要它们。
    【解决方案2】:

    您将无法对您的序列化课程做任何特别的事情 - 这是一个已知问题。此处建议了各种解决方法:

    XmlSerializer: remove unnecessary xsi and xsd namespaces

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

    xml serialization - remove namespace

    【讨论】:

    • 但是我不需要任何特别的东西。我只希望在类中声明的命名空间生效。