为何XContainer.Add方法会给新增元素自动加xmlns属性?如何阻止该行为?
问题根因
你遇到的xmlns=""是XML规范的默认行为:你的根节点<People>设置了默认命名空间https://www.some-random_thing/SuperApp,而你序列化生成的<Person>节点属于空命名空间,当你把空命名空间的节点插入到有默认命名空间的父节点下时,XML会自动给子节点添加xmlns=""声明,用来标识该节点不属于父节点的默认命名空间。
这个属性是保存时自动生成的,不是显式添加到XElement.Attributes集合里的,所以你没办法通过删除属性的方式去掉。
解决方案
方案1:序列化时指定和根节点一致的默认命名空间(最推荐)
直接在序列化Person的时候就指定和根节点相同的命名空间,从根源避免命名空间不一致的问题。
首先修改你的ToXElement扩展方法,支持传入命名空间参数:
public static XElement ToXElement<T>(this object obj, string defaultNamespace = "") { // 初始化序列化器时传入目标命名空间 var serializer = new XmlSerializer(typeof(T), defaultNamespace); XmlSerializerNamespaces xns = new XmlSerializerNamespaces(); // 绑定空前缀到目标命名空间,避免生成不必要的前缀 xns.Add("", string.IsNullOrEmpty(defaultNamespace) ? "" : defaultNamespace); XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, NamespaceHandling = NamespaceHandling.OmitDuplicates, OmitXmlDeclaration = true }; var sw = new StringWriter(); var xmlWriter = XmlWriter.Create(sw, settings); serializer.Serialize(xmlWriter, obj, xns); string xml = sw.ToString(); return XElement.Parse(xml); }
然后在WebMethod中调用时,传入根节点的命名空间即可:
// 取根节点的命名空间传入序列化方法 XElement personEl = newPerson.ToXElement<Person>(doc.Root.Name.NamespaceName); doc.Root.Add(personEl); doc.Save(filePath);
方案2:给Person类加命名空间标注
如果你确定Person类只会用在这个XML结构下,也可以直接给Person类加XmlRoot特性固定命名空间:
[XmlRoot(Namespace = "https://www.some-random_thing/SuperApp")] public class Person { // 原有属性保持不变 public int Id { get; set; } public string Name { get; set; } // 其他属性... }
这种情况下不需要修改ToXElement的调用逻辑,序列化时会自动带上对应命名空间,插入根节点后不会生成xmlns=""。
方案3:手动修改节点命名空间(应急方案)
如果不想改序列化逻辑,也可以在插入节点前,统一修改所有Person相关节点的命名空间和根节点一致:
XElement personEl = PersonXmlHelper.ToXElement<Person>(newPerson); XNamespace rootNs = doc.Root.Name.Namespace; // 递归修改当前节点和所有子节点的命名空间 foreach (var node in personEl.DescendantsAndSelf()) { node.Name = rootNs + node.Name.LocalName; } doc.Root.Add(personEl); doc.Save(filePath);
内容的提问来源于stack exchange,提问作者MrG-O-L
相关产品推荐
相关产品推荐

