Recursively remove xml nodes using Linq to XML

混江龙づ霸主 提交于 2019-12-11 07:29:46

问题


Fairly new to Linq to XML How does one remove xml node( recursively using relation ) and save the document.

Structure of the xml cannot be altered as it comes from service.Below is the xml from a tasks service. Every task can have nested tasks for which there might be one or more nested tasks. Nesting is intended to be upto N level.

  • When one of parent tasks are removed using linq to xml how do i remove all of it's children?

  • How do i know all the nodes where successfully removed?

Xml:

<Tasks>
  <Task ID="1">Clean the Room</Task>
  <Task ID="2">Clean the Closet</Task>
  <Task ID="3" ParentId="2">Remove the toys</Task>
  <Task ID="4" ParentId="3">Stack action Figures on Rack</Task>
  <Task ID="5" ParentId="3">Put soft toys under bed</Task>
</Tasks>

In above xml when taskId=2 is removed, it's sub-tasks namely Id = 3 should be removed. Since 3 is removed it's subtasks 4 and 5 should be removed as well.


回答1:


I'm going to assume that with the xml:

<Tasks> 
  <Task ID="1">Clean the Room</Task>
  <Task ID="2">Clean the Closet</Task>
  <Task ID="3" ParentId="2">Remove the toys</Task>
  <Task ID="4" ParentId="3">Stack action Figures on Rack</Task>
  <Task ID="5" ParentId="3">Put soft toys under bed</Task>

  <Task note="test node" />
  <Task ID="a" note="test node" />
</Tasks>

If Task ID=2 is removed, here is one solution:

// tasks = XDocument.root;

public static void RemoveTasksAndSubTasks(XElement tasks, int id)
{
  List<string> removeIDs = new List<string>();
  removeIDs.Add(id.ToString());

  while (removeIDs.Count() > 0)
  {
    // Find matching Elements to Remove
    // Check for Attribute, 
    // so we don't get Null Refereence Exception checking Value

    var matches = 
        tasks.Elements("Task")
             .Where(x => x.Attribute("ID") != null
                         && removeIDs.Contains(x.Attribute("ID").Value));

    matches.Remove();

    // Find all elements with ParentID 
    // that matches the ID of the ones removed.
    removeIDs = 
        tasks.Elements("Task")
             .Where(x => x.Attribute("ParentId") != null
                         && x.Attribute("ID") != null
                         && removeIDs.Contains(x.Attribute("ParentId").Value))
             .Select(x => x.Attribute("ID").Value)
             .ToList();

  }
}

Result:

<Tasks> 
  <Task ID="1">Clean the Room</Task>

  <Task note="test node" />
  <Task ID="a" note="test node" />
</Tasks>



回答2:


Use following answer

XDocument doc = XDocument.Load("task.xml");
var q = from node in doc.Descendants("Task")
        let attr = node.Attribute("ID")
        let parent = node.Attribute("ParentId")
        where ((attr != null && attr.Value == "3") || (parent != null && parent.Value == "3"))
        select node;
q.ToList().ForEach(x => x.Remove());
doc.Save("output.xml"); 


来源:https://stackoverflow.com/questions/10378498/recursively-remove-xml-nodes-using-linq-to-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!