生成指定XML时触发System.ArgumentException异常求助
问题:生成XML时抛出"无法将节点或其祖先作为自身的子节点插入"异常
尝试通过给定类结构生成目标XML文档,但执行代码时抛出异常:System.ArgumentException: 'Cannot insert a node or any ancestor of that node as a child of itself.',类本身无循环引用,求解决思路。
目标XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <VirtualDesktopManager> <Categories> <Category Name="Category 1"> <Desktops> <Desktop Name="Desktop 1"> <Applications Name="Application 1" /> <Applications Name="Application 2" /> </Desktop> </Desktops> </Category> </Categories> </VirtualDesktopManager>
相关代码
private static void Main () { var database = new Database(); var category = new VirtualDesktopCategory(); var desktop = new VirtualDesktop(); var application = new VirtualDesktopApplication(); category = new VirtualDesktopCategory() { Name = "Cat 1", }; database.Categories.Add(category); desktop = new VirtualDesktop() { Name = "Desktop 1", }; category.Desktops.Add(desktop); application = new VirtualDesktopApplication() { Name = "Application 1", }; desktop.Applications.Add(application); application = new VirtualDesktopApplication() { Name = "Application 2", }; desktop.Applications.Add(application); database.ToXmlDocument().InnerText.Dump(); } public class Database { public string Name { get; set; } = ""; public List<VirtualDesktopCategory> Categories { get; private set; } = new(); public XmlDocument ToXmlDocument() { var document = new XmlDocument(); var xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes"" ?><VirtualDesktopManager></VirtualDesktopManager>"; document.LoadXml(xml); document.DocumentElement?.AppendChild(this.ToXmlElement(document, document.DocumentElement)); return document; } public XmlElement ToXmlElement(XmlDocument document, XmlElement elementParent) { var elementCategories = document.CreateElement("Categories"); elementParent.AppendChild(elementCategories); foreach (var category in this.Categories) { // System.ArgumentException: Cannot insert a node or any ancestor of that node as a child of itself. elementCategories.AppendChild(category.ToXmlElement(document, elementCategories)); } return elementCategories; } } public class VirtualDesktopCategory { public string Name { get; set; } = ""; public List<VirtualDesktop> Desktops { get; private set; } = new(); public XmlElement ToXmlElement(XmlDocument document, XmlElement elementParent) { var elementCategory = document.CreateElement("Category"); var elementDesktops = document.CreateElement("Desktops"); elementCategory.AppendAttribute(document, nameof(this.Name), this.Name); elementParent.AppendChild(elementCategory); elementCategory.AppendChild(elementDesktops); foreach (var desktop in this.Desktops) { elementDesktops.AppendChild(desktop.ToXmlElement(document, elementDesktops)); } return elementCategory; } } public class VirtualDesktop { public string Name { get; set; } = ""; public List<VirtualDesktopApplication> Applications { get; private set; } = new(); public XmlElement ToXmlElement(XmlDocument document, XmlElement elementParent) { var elementDesktop = document.CreateElement("Desktop"); var elementApplications = document.CreateElement("Applications"); elementDesktop.AppendAttribute(document, nameof(this.Name), this.Name); elementParent.AppendChild(elementDesktop); elementDesktop.AppendChild(elementApplications); foreach (var application in this.Applications) { elementApplications.AppendChild(application.ToXmlElement(document, elementApplications)); } return elementParent; } } public class VirtualDesktopApplication { public string Name { get; set; } = ""; public XmlElement ToXmlElement(XmlDocument document, XmlElement elementParent) { var elementApplication = document.CreateElement("Application"); elementApplication.AppendAttribute(document, nameof(this.Name), this.Name); elementParent.AppendChild(elementApplication); return elementApplication; } } public static class Extensions { public static XmlAttribute AppendAttribute(this XmlElement element, XmlDocument document, string name, string value) { var attribute = document.CreateAttribute(name); attribute.Value = value; element.Attributes.Append(attribute); return attribute; } }
解决思路
错误根源
问题出在VirtualDesktop类的ToXmlElement方法返回值上:
其他类(如VirtualDesktopCategory、VirtualDesktopApplication)的ToXmlElement方法都返回自己创建的节点(比如elementCategory、elementApplication),但VirtualDesktop返回的是传入的elementParent(也就是父节点elementDesktops)。
当VirtualDesktopCategory遍历桌面列表时,执行elementDesktops.AppendChild(desktop.ToXmlElement(document, elementDesktops)),相当于尝试把elementDesktops节点作为子节点插入到自身中,直接触发了"无法将节点或其祖先作为自身子节点插入"的异常。
修复代码
修改VirtualDesktop类的ToXmlElement方法,让它返回自己创建的elementDesktop节点,而非elementParent:
public class VirtualDesktop { public string Name { get; set; } = ""; public List<VirtualDesktopApplication> Applications { get; private set; } = new(); public XmlElement ToXmlElement(XmlDocument document, XmlElement elementParent) { var elementDesktop = document.CreateElement("Desktop"); var elementApplications = document.CreateElement("Applications"); elementDesktop.AppendAttribute(document, nameof(this.Name), this.Name); elementParent.AppendChild(elementDesktop); elementDesktop.AppendChild(elementApplications); foreach (var application in this.Applications) { elementApplications.AppendChild(application.ToXmlElement(document, elementApplications)); } // 改为返回自身创建的节点 return elementDesktop; } }
额外优化点
- 目标XML中应用节点是
<Applications>,但代码里创建的是<Application>,若要完全匹配目标格式,需把VirtualDesktopApplication类里的CreateElement("Application")改成CreateElement("Applications")。 Database类的ToXmlDocument方法中原XML字符串存在多余引号转义,已在上述代码中修正为正确格式。
内容的提问来源于stack exchange,提问作者Raheel Khan
相关产品推荐
相关产品推荐

