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

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

我得到的是这:

  1. <?xml ...>
  2. <rootelement xmlns:xsi="..." xmlns:xsd="...">
  3. </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示例。

  1. [XmlRoot("MyTypeWithNamespaces",Namespace="urn:Abracadabra",IsNullable=false)]
  2. public class MyTypeWithNamespaces
  3. {
  4. // As noted below,per Microsoft's documentation,if the class exposes a public
  5. // member of type XmlSerializerNamespaces decorated with the
  6. // XmlNamespacesDeclarationAttribute,then the XmlSerializer will utilize those
  7. // namespaces during serialization.
  8. public MyTypeWithNamespaces( )
  9. {
  10. this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
  11. // Don't do this!! Microsoft's documentation explicitly says it's not supported.
  12. // It doesn't throw any exceptions,but in my testing,it didn't always work.
  13.  
  14. // new XmlQualifiedName(string.Empty,string.Empty),// And don't do this:
  15. // new XmlQualifiedName("","")
  16.  
  17. // DO THIS:
  18. new XmlQualifiedName(string.Empty,"urn:Abracadabra") // Default Namespace
  19. // Add any other namespaces,with prefixes,here.
  20. });
  21. }
  22.  
  23. // If you have other constructors,make sure to call the default constructor.
  24. public MyTypeWithNamespaces(string label,int epoch) : this( )
  25. {
  26. this._label = label;
  27. this._epoch = epoch;
  28. }
  29.  
  30. // An element with a declared namespace different than the namespace
  31. // of the enclosing type.
  32. [XmlElement(Namespace="urn:Whoohoo")]
  33. public string Label
  34. {
  35. get { return this._label; }
  36. set { this._label = value; }
  37. }
  38. private string _label;
  39.  
  40. // An element whose tag will be the same name as the property name.
  41. // Also,this element will inherit the namespace of the enclosing type.
  42. public int Epoch
  43. {
  44. get { return this._epoch; }
  45. set { this._epoch = value; }
  46. }
  47. private int _epoch;
  48.  
  49. // Per Microsoft's documentation,you can add some public member that
  50. // returns a XmlSerializerNamespaces object. They use a public field,// but that's sloppy. So I'll use a private backed-field with a public
  51. // getter property. Also,per the documentation,for this to work with
  52. // the XmlSerializer,decorate it with the XmlNamespaceDeclarations
  53. // attribute.
  54. [XmlNamespaceDeclarations]
  55. public XmlSerializerNamespaces Namespaces
  56. {
  57. get { return this._namespaces; }
  58. }
  59. private XmlSerializerNamespaces _namespaces;
  60. }

这就是这个类。现在,有人反对在他们的类中有一个XmlSerializerNamespaces对象;但是你可以看到,我整洁地把它放在默认构造函数中,并暴露了一个公共属性来返回命名空间。

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

  1. MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel",42);
  2.  
  3. /******
  4. OK,I just figured I could do this to make the code shorter,so I commented out the
  5. below and replaced it with what follows:
  6.  
  7. // You have to use this constructor in order for the root element to have the right namespaces.
  8. // If you need to do custom serialization of inner objects,you can use a shortened constructor.
  9. XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),new XmlAttributeOverrides(),new Type[]{},new XmlRootAttribute("MyTypeWithNamespaces"),"urn:Abracadabra");
  10.  
  11. ******/
  12. XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
  13.  
  14. // I'll use a MemoryStream as my backing store.
  15. MemoryStream ms = new MemoryStream();
  16.  
  17. // This is extra! If you want to change the settings for the XmlSerializer,you have to create
  18. // a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
  19. // So,in this case,I want to omit the XML declaration.
  20. XmlWriterSettings xws = new XmlWriterSettings();
  21. xws.OmitXmlDeclaration = true;
  22. xws.Encoding = Encoding.UTF8; // This is probably the default
  23. // You could use the XmlWriterSetting to set indenting and new line options,but the
  24. // XmlTextWriter class has a much easier method to accomplish that.
  25.  
  26. // The factory method returns a XmlWriter,not a XmlTextWriter,so cast it.
  27. XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms,xws);
  28. // Then we can set our indenting options (this is,of course,optional).
  29. xtw.Formatting = Formatting.Indented;
  30.  
  31. // Now serialize our object.
  32. xs.Serialize(xtw,myType,myType.Namespaces);

一旦你这样做,你应该得到以下输出

  1. <MyTypeWithNamespaces>
  2. <Label xmlns="urn:Whoohoo">myLabel</Label>
  3. <Epoch>42</Epoch>
  4. </MyTypeWithNamespaces>

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

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

更新:我只是想确保我回答OP的问题,删除所有命名空间。我的代码上面将工作为此;让我告诉你怎么样。现在,在上面的例子中,你真的不能摆脱所有命名空间(因为有两个命名空间在使用)。在你的XML文档中的某个地方,你将需要一些类似于xmlns =“urn:Abracadabra”xmlns:w =“urn:Whoohoo。如果示例中的类是更大的文档的一部分,必须为Abracadbra和Whoohoo中的任何一个(或两者)声明。如果不是,那么一个或两个命名空间中的元素必须用某种类型的前缀来装饰(你不能有两个默认命名空间,对吗?因此,对于这个例子,Abracadabra是默认的命名空间,我可以在MyTypeWithNamespaces类中为Whoohoo命名空间添加命名空间前缀,如下所示:

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

现在,在我的类定义中,我指出< Label />元素在命名空间“urn:Whoohoo”中,因此我不需要进一步做任何事。当我现在序列化类使用我上面的序列化代码不变,这是输出

  1. <MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
  2. <w:Label>myLabel</w:Label>
  3. <Epoch>42</Epoch>
  4. </MyTypeWithNamespaces>

因为< Label>在与文档的其余部分不同的命名空间中,它在某种程度上必须用命名空间“装饰”。请注意,仍然没有xsi和xsd命名空间。

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

  1. <MyTypeWithNamespaces>
  2. <Label>myLabel<Label>
  3. <Epoch>42</Epoch>
  4. </MyTypeWithNamespaces>

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

  1. // As noted below,if the class exposes a public
  2. // member of type XmlSerializerNamespaces decorated with the
  3. // XmlNamespacesDeclarationAttribute,then the XmlSerializer will utilize those
  4. // namespaces during serialization.
  5. public MyTypeWithNamespaces( )
  6. {
  7. this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
  8. new XmlQualifiedName(string.Empty,"urn:Abracadabra") // Default Namespace
  9. });
  10. }
  11.  
  12. [XmlNamespaceDeclarations]
  13. public XmlSerializerNamespaces Namespaces
  14. {
  15. get { return this._namespaces; }
  16. }
  17. private XmlSerializerNamespaces _namespaces;

然后,稍后,在使用MyTypeWithNamespaces对象将其序列化的代码中,您将调用它,如上所述:

  1. MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel",42);
  2.  
  3. XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
  4.  
  5. ...
  6.  
  7. // Above,you'd setup your XmlTextWriter.
  8.  
  9. // Now serialize our object.
  10. xs.Serialize(xtw,myType.Namespaces);

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

  1. <MyTypeWithNamespaces>
  2. <Label>myLabel<Label>
  3. <Epoch>42</Epoch>
  4. </MyTypeWithNamespaces>

猜你在找的XML相关文章