【问题标题】:Recursively remove xml nodes using Linq to XML使用 Linq to XML 递归删除 xml 节点
【发布时间】:2012-04-30 04:28:11
【问题描述】:

Linq to XML 的新手如何删除 xml 节点(递归使用关系)并保存文档。

xml 的结构无法更改,因为它来自服务。以下是来自任务服务的 xml。每个任务都可以有嵌套任务,其中可能有一个或多个嵌套任务。嵌套旨在达到N level。

  • 当使用 linq to xml 删除其中一个父任务时,我如何删除它的所有子任务?

  • 我如何知道成功移除的所有节点?

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>

在上面的xml中,当taskId=2被删除时,它的子任务即Id = 3应该被删除。由于3 被删除,它的子任务4 和5 也应该被删除。

【问题讨论】:

  • 我不明白你的结构。您声明如果应该删除Task=1、2,3,4,5,但它们都没有ParentID=1。你是说Task=2 吗?
  • @ErikPhilips 很抱歉造成混乱。任务通过 parentid 属性与另一个任务相关联。因此,当删除带有ID = 2 的任务时,它的子任务(带有ParentId = 2 的任务)也应该被删除。这个过程一直持续到当前删除的任务没有节点为止。

标签: c# xml linq file-io linq-to-xml


【解决方案1】:

我将假设使用 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>

如果Task ID=2 被删除,这是一种解决方案:

// 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();

  }
}

结果:

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

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

【讨论】:

    【解决方案2】:

    使用以下答案

    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"); 
    

    【讨论】:

    • 我认为这会删除带有ID = 1 的Task 节点,这不是我要求的。由于 ID = 1 的任务被删除,我如何删除它的依赖任务?具有parentId = 1 的任务和父 ID 等于其 parentId = '1' 的任务的任务?明白了
    • 我已经在 where linq 中编辑了他的比较父 id 属性的答案。此外,dere 需要对父 ID 属性进行空检查
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多