有没有办法配置XmlSerializer,使其不会在根元素中写入默认名称空间?

我得到的是:

<?xml ...>
<rootelement xmlns:xsi="..." xmlns:xsd="...">
</rootelement>

我想删除这两个xmlns声明.

Duplicate of: How to serialize an object to XML without getting xmlns=”…”?

推荐答案

自从Dave让我重复我的答案到Omitting all xsi and xsd namespaces when serializing an object in .NET,我已经更新了这篇帖子,并在上面提到的链接中重复了我的答案.这个答案中使用的例子与另一个问题中使用的例子相同.下面是逐字复制的内容.


在网上阅读了微软的文档和几个解决方案后,我发现了这个问题的解决方案.它通过IXmlSerialiazble与内置XmlSerializer和自定义XML序列化一起工作.

简而言之,我将使用到目前为止在回答这个问题时使用的相同的MyTypeWithNamespacesXML示例.

[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
    // As noted below, per Microsoft's documentation, if the class exposes a public
    // member of type XmlSerializerNamespaces decorated with the 
    // XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
    // namespaces during serialization.
    public MyTypeWithNamespaces( )
    {
        this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
            // Don't do this!! Microsoft's documentation explicitly says it's not supported.
            // It doesn't throw any exceptions, but in my testing, it didn't always work.

            // new XmlQualifiedName(string.Empty, string.Empty),  // And don't do this:
            // new XmlQualifiedName("", "")

            // DO THIS:
            new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
            // Add any other namespaces, with prefixes, here.
        });
    }

    // If you have other constructors, make sure to call the default constructor.
    public MyTypeWithNamespaces(string label, int epoch) : this( )
    {
        this._label = label;
        this._epoch = epoch;
    }

    // An element with a declared namespace different than the namespace
    // of the enclosing type.
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        get { return this._label; }
        set { this._label = value; }
    }
    private string _label;

    // An element whose tag will be the same name as the property name.
    // Also, this element will inherit the namespace of the enclosing type.
    public int Epoch
    {
        get { return this._epoch; }
        set { this._epoch = value; }
    }
    private int _epoch;

    // Per Microsoft's documentation, you can add some public member that
    // returns a XmlSerializerNamespaces object. They use a public field,
    // but that's sloppy. So I'll use a private backed-field with a public
    // getter property. Also, per the documentation, for this to work with
    // the XmlSerializer, decorate it with the XmlNamespaceDeclarations
    // attribute.
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces Namespaces
    {
        get { return this._namespaces; }
    }
    private XmlSerializerNamespaces _namespaces;
}

这节课到此为止.现在,一些人反对在他们的类中有一个XmlSerializerNamespaces对象;但正如您所见,我将其巧妙地隐藏在默认构造函数中,并公开了一个公共属性以返回名称空间.

现在,当需要序列化该类时,您将使用以下代码:

MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);

/******
   OK, I just figured I could do this to make the code shorter, so I commented out the
   below and replaced it with what follows:

// You have to use this constructor in order for the root element to have the right namespaces.
// If you need to do custom serialization of inner objects, you can use a shortened constructor.
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces), new XmlAttributeOverrides(),
    new Type[]{}, new XmlRootAttribute("MyTypeWithNamespaces"), "urn:Abracadabra");

******/

/*****
  Per @dbc, since MyTypeWithNamespaces has a XmlRootAttribute decorating the class,
  You may be able to get away with NOT using this .ctor and use the simple
  XmlSerializer(Type) .ctor.
  Also, be careful not to use serializer creation in loops, as it could lead
  to extensive memory issues due to how serializers are cached (or not...).
  See @dbc's comment and link to SO Q&A for more details.

XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
****/
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces));

// I'll use a MemoryStream as my backing store.
MemoryStream ms = new MemoryStream();

// This is extra! If you want to change the settings for the XmlSerializer, you have to create
// a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
// So, in this case, I want to omit the XML declaration.
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8; // This is probably the default
// You could use the XmlWriterSetting to set indenting and new line options, but the
// XmlTextWriter class has a much easier method to accomplish that.

// The factory method returns a XmlWriter, not a XmlTextWriter, so cast it.
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
// Then we can set our indenting options (this is, of course, optional).
xtw.Formatting = Formatting.Indented;

// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);

完成此操作后,应获得以下输出:

<MyTypeWithNamespaces>
    <Label xmlns="urn:Whoohoo">myLabel</Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

在最近的一个项目中,我成功地使用了此方法,其中的类被序列化为用于Web服务调用的XML的深层层次 struct .微软的文档不是很清楚,一旦你创建了可公开访问的XmlSerializerNamespaces个成员,该怎么做,所以很多人认为它是无用的.但是,通过遵循他们的文档并以上面所示的方式使用它,您可以定制XmlSerializer如何为您的类生成XML,而无需诉诸不受支持的行为或通过实现IXmlSerializable来"滚动"您自己的序列化.

我希望这个答案将一劳永逸地解决如何摆脱XmlSerializer生成的标准xsixsd名称空间的问题.

更新:我只是想确保我回答了OP关于删除所有名称空间的问题.我上面的代码适用于此;让我告诉你怎么做.现在,在上面的示例中,您真的无法摆脱所有名称空间(因为有两个名称空间正在使用).在XML文档中的某个地方,需要有大约xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo个.如果示例中的类是较大文档的一部分,则必须为AbracadbraWhoohoo中的一个(或两者)声明命名空间上方的某个位置.如果没有,那么一个或两个名称空间中的元素必须用某种前缀修饰(不能有两个默认名称空间,对吗?).因此,在这个例子中,Abracadabra是默认名称空间.我可以在MyTypeWithNamespaces类中为Whoohoo名称空间添加名称空间前缀,如下所示:

public MyTypeWithNamespaces
{
    this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
        new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
        new XmlQualifiedName("w", "urn:Whoohoo")
    });
}

现在,在我的类定义中,我指出<Label/>元素在名称空间"urn:Whoohoo"中,所以我不需要做任何进一步的事情.当我现在使用上述序列化代码对类进行序列化时,结果如下:

<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
    <w:Label>myLabel</w:Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

因为<Label>与文档的其余部分位于不同的名称空间中,所以它必须以某种方式用名称空间"修饰".请注意,仍然没有xsixsd名称空间.


我对另一个问题的回答到此为止.但我想确保我回答了OP关于不使用名称空间的问题,因为我觉得我还没有真正解决这个问题.假设<Label>与文档的其余部分属于同一名称空间,在本例中为urn:Abracadabra:

<MyTypeWithNamespaces>
    <Label>myLabel<Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

您的构造函数将与我的第一个代码示例中的一样,并带有检索默认名称空间的公共属性:

// As noted below, per Microsoft's documentation, if the class exposes a public
// member of type XmlSerializerNamespaces decorated with the 
// XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
// namespaces during serialization.
public MyTypeWithNamespaces( )
{
    this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
        new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
    });
}

[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
    get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;

然后,稍后,在使用MyTypeWithNamespaces对象对其进行序列化的代码中,您可以像上面那样调用它:

MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);

XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });

...

// Above, you'd setup your XmlTextWriter.

// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);

XmlSerializer将返回与上面立即显示的相同的XML,并且在输出中没有额外的名称空间:

<MyTypeWithNamespaces>
    <Label>myLabel<Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

.net相关问答推荐

为什么这个同步运行的异步睡眠会挂起?

将 Span 传递到函数时出现 F# 错误

MongoDB GridFs with C#,如何存储图片等文件?

是否可以将 SandCastle 创建的两个页面合并到一个主页中?

为什么不能使用 null 作为 Dictionary 的键?

无法加载文件或程序集 Microsoft.Extensions.DependencyInjection.Abstractions,版本 = 1.1.0.0

string.Format 如何处理空值?

在 C# 中将字节数组保存为磁盘上的文件的最有效方法是什么?

如何授予所有用户对我的应用程序创建的文件的完全权限?

WCF服务客户端:内容类型text/html;响应消息的charset=utf-8 与绑定的内容类型不匹配

String.Format - 它是如何工作的以及如何实现自定义格式字符串

Find() 和 First() 抛出异常,如何改为返回 null?

.NET Framework SDK 和 Targeting 包有什么区别

将记录器作为单身人士是一个好习惯吗?

C# List<> 按 x 然后 y 排序

如何在 nuspec 中指定特定的依赖版本?

MailMessage,Sender 和 From 属性的区别

读取 XML(从字符串)并获取一些字段 - 读取 XML 时出现问题

ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?

如果选中,则更改列表框项的 WPF DataTemplate