17370845950

C#如何使用XmlSerializerNamespaces移除不必要的命名空间
要彻底移除XmlSerializer生成的xmlns:xsi和xmlns:xsd声明,需使用XmlSerializerNamespaces并调用Add("", "")覆盖默认命名空间映射,同时确保所有Xml特性未设置Namespace属性。

在使用 XmlSerializer 序列化对象为 XML 时,.NET 默认会自动添加 xmlns:xsixmlns:xsd 等命名空间声明,即使你没显式定义任何命名空间。这些声明对某些系统(如轻量级 API、遗留系统或严格校验的 XML Schema)来说是冗余甚至不兼容的。要彻底移除它们,关键不是“过滤”输出,而是**从序列化源头控制命名空间的注入行为**——XmlSerializerNamespaces 就是为此设计的。

明确清空默认命名空间声明

XmlSerializerNamespaces 本身不“移除”已有命名空间,而是**覆盖**序列化器默认使用的命名空间映射。它的核心用法是传入一个包含空前缀映射的实例:

  • 创建 XmlSerializerNamespaces 实例
  • 调用 .Add("", "") —— 第一个空字符串表示“默认命名空间前缀”,第二个空字符串表示“不绑定到任何 URI”
  • 将该实例传给 XmlSerializer.Serialize() 的重载方法

这样,序列化器就不会再自动添加 xsixsd 声明,因为你的命名空间表已显式接管了默认行为。

配合 XmlSerializerSettings 禁用 xsi/xsd(.NET Core/.NET 5+ 推荐)

在较新版本中,更直接的方式是使用 XmlWriterSettings 配合 XmlSerializer,尤其当你要完全跳过类型信息序列化时:

  • 设置 XmlWriterSettings.OmitXmlDeclaration = false(按需)
  • 设置 XmlWriterSettings.NamespaceHandling = NamespaceHandling.OmitDuplicates(辅助去重)
  • 关键:使用 XmlSerializer.Serialize(XmlWriter, object, XmlSerializerNamespaces) 并传入 new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") })

注意:XmlSerializer 不支持像 XmlWriterSettings 那样全局禁用 xsi/xsd,所以必须配合 XmlSerializerNamespaces 显式覆盖。

避免 [XmlRoot] 或 [XmlElement] 中意外引入命名空间

即使用了 XmlSerializerNamespaces,如果类成员上写了类似 [XmlElement(Namespace = "http://example.com")][XmlRoot(Namespace = "urn:myapp")],序列化器仍会生成对应命名空间前缀和声明。要真正“无命名空间”,需确保:

  • 所有 [Xml*] 特性中 Namespace 属性未设置,或显式设为 ""
  • 类本身未继承自带命名空间的基类(如 WCF 生成的类)
  • 若使用 [XmlRoot],检查其 Namespace 是否为空字符串

验证输出是否干净

序列化后不要只看字符串是否含 xmlns:,而应检查实际 XML 结构:

  • 开头不应出现 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  • 不应出现 xsi:typexsi:nil 属性(除非你主动写入)
  • 根元素应无前缀,且无隐式默认命名空间声明(如 xmlns="" 是允许的,表示“此元素及其子元素属于无命名空间”,不是冗余项)

可将结果加载进 XDocument 并检查 Root.Name.Namespace 是否为 XNamespace.None 来确认。