Linq to XML:如何删除值不在另一个集合中的节点

时间:2013-10-16 14:01:35

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

我有一个xml文档,其中包含一个包含用户节点列表的节点,以及一个包含具有用户列表的组的节点。我想删除users集合中没有匹配的dn的所有节点。

作为下面简化结构中的一个例子,我试图删除所有deleteme,用户节点。

<?xml version="1.0" encoding="utf-8"?>
<syncdata >
  <users >
    <user>
      <dn>deleteme1</dn>      
    </user>
    <user>
      <dn>deleteme2</dn>      
    </user>
    <user>
      <dn>deleteme3</dn>      
    </user>
    <user>
      <dn>JohnSmith</dn>      
    </user> 
  </users>
  <groups>
  <group name="group2">     
      <users>
        <user>
          <dn>JohnSmith</dn>
        </user>
      </users>
    </group>
    <group name="group1">      
      <users>
        <user>
          <dn>JohnDoe</dn>
        </user>
        <user>
          <dn>JohnnyMorris</dn>
        </user>        
      </users>
    </group>
</groups>
  </syncdata>  

下面的代码删除了syncdata / users集合中的所有项目,我需要执行与不存在的SQL类似的操作。

System.Xml.Linq.XDocument xdoc
 xdoc.Descendants("users").Where(F => F.Parent.Name == "syncdata").Descendants("user").Where(u => u.Parent.Name == "users").Remove();

这可能吗?

3 个答案:

答案 0 :(得分:4)

var xDoc = XDocument.Load(fname);

HashSet<string> set = new HashSet<string>(xDoc.Root.Element("groups")
                                              .Descendants("dn")
                                              .Select(dn => (string)dn));

foreach (var user in xDoc.Root.Element("users").Elements("user").ToList())
{
    if(!set.Contains(user.Element("dn").Value))
        user.Remove();
}

var newXml = xDoc.ToString();

答案 1 :(得分:3)

获得2个收藏的简单且更可靠的方式:

var users = xDoc.Element("syncdata").Element("users")
            .Elements("user").ToList();  // cache in list

var userNamesInGroups = xDoc.Element("syncdata").Element("groups")
           .Descendants("user").Element("dn").Value;

var usersToDelete = users
           .Where(u => ! userNamesInGroups.Contains(u.Element("dn").Value)); 

 foreach(var user in usersToDelete)
     user.Remove();

答案 2 :(得分:0)

string xml = @"<?xml version='1.0' encoding='utf-8'?>
    <syncdata >
      <users >
        <user>
          <dn>JohnDoe</dn>      
        </user>
        <user>
          <dn>deleteme2</dn>      
        </user>
        <user>
          <dn>deleteme3</dn>      
        </user>
        <user>
          <dn>JohnSmith</dn>      
        </user> 
      </users>
      <groups>
        <group name='group2'>     
          <users>
            <user>
              <dn>JohnSmith</dn>
            </user>
          </users>
        </group>
        <group name='group1'>      
          <users>
            <user>
              <dn>JohnDoe</dn>
            </user>
            <user>
              <dn>JohnnyMorris</dn>
            </user>        
          </users>
        </group>
      </groups>
    </syncdata>  ";

    var doc = XDocument.Parse(xml); 

    var groupUsersList =  doc.Root.Element("groups")
                                   .Descendants("dn")
                                   .Select(x => (string)x)
                                   .ToList();

    var users = doc.Root.Element("users").Elements("user").ToList();
    foreach (var user in users )
    {
        if(!groupUsersList.Contains(user.Element("dn").Value))
            user.Remove();
    }

    Console.WriteLine(doc.ToString());
    // prints <syncdata>
    //          <users>
    //             <user>
    //               <dn>JohnDoe</dn>
    //              </user>
    //              <user>
    //               <dn>JohnSmith</dn>
    //              </user>
    //           </users>
    //          <groups>...