.net – XmlSerializer:删除不必要的xsi和xsd命名空间

前端之家收集整理的这篇文章主要介绍了.net – XmlSerializer:删除不必要的xsi和xsd命名空间前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
是否有一种方法来配置XmlSerializer,使其不在根元素中写入默认名称空间?

我得到的是这:

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

并且我想删除两个xmlns声明。

重复:How to serialize an object to XML without getting xmlns=”…”?

由于Dave要求我重复我的答案 Omitting all xsi and xsd namespaces when serializing an object in .NET,我更新了这篇文章,并从上述链接重复我的回答。此答案中使用的示例与用于其他问题的示例相同。以下是逐字复制的。

阅读Microsoft的文档和几个解决方案在线,我已经发现了这个问题的解决方案。它与内置的XmlSerializer和自定义XML序列化通过IXmlSerialiazble工作。

为了白,我将使用迄今为止在此问题的答案中使用的相同的MyTypeWithNamespaces XML示例。

[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");

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

// 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>

我已经成功地在最近的一个项目中使用这种方法,一个深入层次的类被序列化为XML的Web服务调用。微软的文档不太清楚在公开访问的XmlSerializerNamespaces成员一旦你创建它,怎么办,很多人认为它是无用的。但是通过遵循它们的文档并以上面所示的方式使用它们,您可以定制XmlSerializer如何为您的类生成XML,而不使用不支持的行为或通过实现IXmlSerializable“滚动自己的”序列化。

我希望这个答案将永远搁置,如何摆脱XmlSerializer生成的标准xsi和xsd命名空间。

更新:我只是想确保我回答OP的问题,删除所有命名空间。我的代码上面将工作为此;让我告诉你怎么样。现在,在上面的例子中,你真的不能摆脱所有命名空间(因为有两个命名空间在使用)。在你的XML文档中的某个地方,你将需要一些类似于xmlns =“urn:Abracadabra”xmlns:w =“urn:Whoohoo。如果示例中的类是更大的文档的一部分,必须为Abracadbra和Whoohoo中的任何一个(或两者)声明。如果不是,那么一个或两个命名空间中的元素必须用某种类型的前缀来装饰(你不能有两个默认命名空间,对吗?因此,对于这个例子,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>在与文档的其余部分不同的命名空间中,它在某种程度上必须用命名空间“装饰”。请注意,仍然没有xsi和xsd命名空间。

这结束了我对另一个问题的回答。但我想确保我回答OP的问题,使用没有命名空间,因为我觉得我还没有真正解决它。假设< Label>是与文档的其余部分相同的命名空间的一部分,在这种情况下urn:Abracadabra:

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

你的构造函数看起来像在我的第一个代码示例,以及检索默认命名空间的public属性

// As noted below,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.Namespaces);

并且XmlSerializer会吐出与上面刚刚显示的相同的XML,在输出中没有额外的命名空间:

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

猜你在找的XML相关文章