xmlserializer 默认添加 xmlns:xsi 和 xmlns:xsd 命名空间,需通过 xmlserializernamespaces 显式清空:创建 serializer 后,新建 xmlserializernamespaces 并调用 ns.add("", ""),再将 ns 作为第三个参数传入 serialize 方法。

XmlSerializer 默认会加 xmlns,怎么关掉
默认用 XmlSerializer 序列化对象时,生成的 XML 顶部总带 xmlns:xsi 和 xmlns:xsd,甚至还有空的 xmlns=""。这不是 bug,是 .NET 的默认行为——它想帮你声明 schema 兼容性,但多数 API 或配置文件根本不需要。
关键不是“能不能去掉”,而是“必须在构造 XmlSerializer 时不传 XmlRootAttribute,且序列化时用 XmlSerializerNamespaces 显式清空”。
- 直接 new
XmlSerializer(typeof(MyClass))→ 必然带命名空间 - 哪怕类上打了
[XmlRoot(Namespace = "")],也不管用 - 真正起效的是:序列化时传入一个装了空前缀的
XmlSerializerNamespaces
最简代码:三行搞定无命名空间 XML
不用改类定义,不依赖第三方库,纯原生写法:
var serializer = new XmlSerializer(typeof(MyClass));
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // 关键:空前缀映射到空字符串
serializer.Serialize(writer, obj, ns);
注意:ns.Add("", "") 这一行不能省,也不能写成 ns.Add(string.Empty, string.Empty)(虽然等价,但可读性差);更不能漏掉第三个参数 ns —— 不传就回退到默认带命名空间行为。
-
writer可以是StringWriter、FileStream或XmlTextWriter - 如果用
XmlTextWriter,记得设Formatting = Formatting.Indented,否则输出无换行缩进 - 这个方法对嵌套对象、集合、属性级
[XmlElement]全部生效
为什么 [XmlRoot(Namespace="")] 不起作用
很多人试过在类上加 [XmlRoot(Namespace = "")] 或 [XmlType(Namespace = "")],结果 XML 里还是有 xmlns=""。这是因为:该特性只控制根元素是否显式声明默认命名空间,而 XmlSerializer 内部仍会为 xsi/xsd 插入标准命名空间,除非你主动用 XmlSerializerNamespaces 覆盖。
-
Namespace = ""≠ “禁用所有命名空间”,只是说“我不指定目标命名空间” - xsi/xsd 是序列化器自动注入的,和你的类定义无关
- 只有
XmlSerializerNamespaces是唯一能压制这些自动注入的开关
要注意的兼容性坑:反序列化时别乱删命名空间
如果你把序列化出来的无命名空间 XML 拿去反序列化,只要结构没变,XmlSerializer.Deserialize() 完全不受影响——它根本不关心输入里有没有 xmlns。
但反过来,如果上游给你的 XML 带命名空间(比如 xmlns="http://example.com/ns"),而你没在类上配 [XmlRoot(Namespace = "http://example.com/ns")],就会反序列化失败,报错类似:There is an error in XML document (2, 2)。
- 序列化去命名空间是安全的;反序列化认命名空间是严格的
- 别为了“统一风格”把别人给的带命名空间 XML 手动删掉
xmlns再喂给Deserialize - 真要处理混合命名空间,得用
XmlDocument或XDocument预处理,而不是硬扛










