删除序列化程序创建的空xmlns

我有一个由“添加服务引用…”操作生成的对象,我手动使用我编写的通用序列化程序对其进行序列化。

我的问题是数据契约有一些内部对象。

序列化程序将空名称空间属性添加到内部对象的起始标记。 有没有办法阻止这种情况发生?

如何使内部对象与根目录属于同一名称空间? 这样,从后代中省略xmlns声明是正确的。 您可以使用[assembly: ContractNamespace]属性覆盖程序集中所有合同的名称空间。 有关示例,请参阅数据合同名称 。

编辑 :下面的一些例子详细说明。

假设您手动构建XML文档,并且不为任何元素指定命名空间。

 XDocument xmlDocument = new XDocument( new XElement("Book", new XElement("Title", "Animal Farm"), new XElement("Author", "George Orwell"), new XElement("Publisher", new XElement("Name", "Secker and Warburg"), new XElement("Location", "London"), new XElement("Founded", 1910)))); return xmlDocument.ToString(); 

正如所料,生成的XML将没有名称空间声明:

  Animal Farm George Orwell  Secker and Warburg London 1910   

但是,如果仅为根元素指定命名空间,则所有子元素必须使用xml=""明显式地从该默认命名空间中恢复。 根据命名空间默认规则:

默认命名空间声明的范围从它出现的start-tag的开头延伸到相应的end-tag的末尾,不包括任何内部默认命名空间声明的范围。 对于空标记,范围是标记本身。

因此,以下代码(具有为根元素指定的命名空间)…

 XDocument xmlDocument = new XDocument( new XElement("{http://example.com/library}Book", new XElement("Title", "Animal Farm"), new XElement("Author", "George Orwell"), new XElement("Publisher", new XElement("Name", "Secker and Warburg"), new XElement("Location", "London"), new XElement("Founded", 1910)))); return xmlDocument.ToString(); 

…将提供以下XML:

  Animal Farm George Orwell  Secker and Warburg London 1910   

请注意元素的子元素如何不需要从根的命名空间中恢复,因为它们从父元素inheritance了“无命名空间”声明。

为了消除xmlns=""声明,为了演示,我们可以为所有后代分配相同的命名空间:

 XDocument xmlDocument = new XDocument( new XElement("{http://example.com/library}Book", new XElement("{http://example.com/library}Title", "Animal Farm"), new XElement("{http://example.com/library}Author", "George Orwell"), new XElement("{http://example.com/library}Publisher", new XElement("{http://example.com/library}Name", "Secker and Warburg"), new XElement("{http://example.com/library}Location", "London"), new XElement("{http://example.com/library}Founded", 1910)))); return xmlDocument.ToString(); 

这将为XML文档提供仅在根中声明的名称空间(并在所有后代中隐式inheritance):

  Animal Farm George Orwell  Secker and Warburg London 1910   

为了模仿涉及Web服务的场景,我们可以创建以下WCF服务。

 [DataContract] public class Book { [DataMember] public string Title { get; set; } [DataMember] public string Author { get; set; } [DataMember] public Publisher Publisher { get; set; } } [DataContract] public class Publisher { [DataMember] public string Name { get; set; } [DataMember] public string Location { get; set; } [DataMember] public short Founded { get; set; } } [ServiceContract] public interface ILibraryService { [OperationContract] Book GetBook(); } public class LibraryService : ILibraryService { public Book GetBook() { return new Book { Title = "Animal Farm", Author = "George Orwell", Publisher = new Publisher { Name = "Secker and Warburg", Location = "London", Founded = 1910, } }; } } 

我们在客户端应用程序中添加对上述服务的服务引用,使用它的操作,并将结果序列化,同时将其封装在具有显式命名空间的根Books元素中:

 using (var libraryClient = new LibraryServiceReference.LibraryServiceClient()) { var book = libraryClient.GetBook(); var stringBuilder = new StringBuilder(); using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder)) { xmlWriter.WriteStartElement("Books", "http://example.com/library"); var serializer = new XmlSerializer(book.GetType()); serializer.Serialize(xmlWriter, book); xmlWriter.WriteEndElement(); } return stringBuilder.ToString(); } 

在这种情况下,内部元素Book包含xmlns=""声明。

     George Orwell   1910 London Secker and Warburg  Animal Farm   

如上所述,可以通过将Book元素的名称空间(及其后代的名称空间)设置为与根目录相对应来消除此xmlns="" 。 对于XmlSerializer类,可以通过其构造函数的第二个参数指定所有元素的默认命名空间。 (实际技术会根据您使用的序列化策略而有所不同。)

 using (var libraryClient = new LibraryServiceReference.LibraryServiceClient()) { var book = libraryClient.GetBook(); var stringBuilder = new StringBuilder(); using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder)) { xmlWriter.WriteStartElement("Books", "http://example.com/library"); var serializer = new XmlSerializer(book.GetType(), "http://example.com/library"); serializer.Serialize(xmlWriter, book); xmlWriter.WriteEndElement(); } return stringBuilder.ToString(); } 

这将产生预期的结果:

     George Orwell   1910 London Secker and Warburg  Animal Farm   

如果您可以控制序列化程序,则可以始终添加null命名空间以确保从输出XML中省略xmlns。 例如:

 var serializer = new XmlSerializer(target.GetType()); var ns = new XmlSerializerNamespaces(); ns.Add("",""); serializer.Serialize(xmlWriter, target, ns); 

最好的祝福,

这可能有点偏离主题,如果您正在使用[DataContract] ,则可能不适用。 相反,这适用于从WSDL生成的代理代码(在具有Java端点的互操作环境中,我们被告知xmlns =“”无效)。 所以我把它放在那里以防它有帮助。

当设置为System.Xml.Schema.XmlSchemaForm.Unqualified时, XmlElementAttribute.Form属性可以导致WCF请求中的子成员输出xmlns =“”。

 [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] public string MyProperty { get; set; } 

它产生了一些东西

  My value goes here  

将其设置为System.Xml.Schema.XmlSchemaForm.None (这是默认值)意味着它不会输出“不合格”的命名空间属性。

 [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.None)] public string MyProperty { get; set; } 

产生这个:

  My value goes here  

我不确定你是否可以在导入wsdl引用时更改此行为,或者可能wsdl应该已经更改,但我最终直接编辑生成的代理代码(这绝对不是理想的),但实现了我的直接目标。