c#查找匹配两个元素级别的xml元素

本文关键字:元素 两个 xml 查找 | 更新日期: 2023-09-27 18:11:40

我试图从xml文档中选择一个XElement并在xml文档的两个"级别"上进行匹配。我的文件结构是:

<app>
  <Library Name="Main" Path="C:'somefile.Xml">
    <ReadingList Name="Test1">
      <Book>...
    <ReadingList Name="Test2">
      <Book>...
  <Library Name="Backup" Path="C:'somefile.Xml">

我想在库"Main"中找到阅读列表名称"test2",所以我可以将该元素和所有子元素复制到另一个库节点。

我更喜欢使用linq的解决方案,因为我正在努力学习这个。

提前感谢您的帮助

当我添加一个新的"阅读列表"时,我这样做:

public void AddReadingList(string fullyQualifiedPath, Library lib, string name)
{
    XDocument xdoc = XDocument.Load(fullyQualifiedPath);
    XElement library = xdoc.Element("eStack").Elements("Library")
                .Single(x => x.Attribute("Name").Value == lib.Name);
    library.Add(new XElement("ReadingList", new XAttribute("Name", name)));
    xdoc.Save(fullyQualifiedPath);                        
}

,但我要执行的操作是复制该元素和子元素。问题是,可能有多个"library"元素具有相同的名称,所以我需要检查图书馆名称和阅读列表名称。明白了吗?

c#查找匹配两个元素级别的xml元素

使用.DescendantsWhere s的组合将达到目的:

var result = XDocument.Load(fullyQualifiedPath)
     .Descendants("Library")
         //Can replace with `FirstOrDefault` if you know there is only one
     .Where(element => element.Attribute("Name")?.Value == "Main") 
     .Descendants("ReadingList")
     .Where(element => element.Attribute("Name")?.Value == "Test2").ToList();

你也可以用.Elements来代替Descendants,我只是更喜欢用它,这样就不用指定app或任何其他的水平。


对于以前的c# 6.0,可以这样做:

var result = XDocument.Load("data.xml")
     .Descendants("Library")
     .Where(element =>
     {
        var att = element.Attribute("Name");
        return att != null ? (att.Value == "Main" ? true : false) : false;
     })
     .Descendants("ReadingList")
         //Make sure to do above change here too
     .Where(element => element.Attribute("Name")?.Value == "Test2").ToList();

或者创建一个方法来帮助解决这个问题,而不是重复代码:

 Func<XElement, string, string> tryGetAttributeValue = (element, attributeName) =>
 {
    var attribute = element.Attribute(attributeName);
    return attribute == null ? string.Empty : attribute.Value;
 };
 var result = XDocument.Load("data.xml")
     .Descendants("Library")
     .Where(element => tryGetAttributeValue(element,"Name") == "Main")
     .Descendants("ReadingList")
     .Where(element => tryGetAttributeValue(element, "Name") == "Test2").ToList();

您也可以这样查询:

var query=  xdoc.Descendants("Library")
                .Where(e=>e.Attribute("Name").Value=="Main")
                .SelectMany(e=>e.Elements("ReadingList").Where(t=>t.Attribute("Name").Value=="Test2"));

如果只有一个Main元素,你也可以使用FirstOrDefault扩展方法:

var query=  xdoc.Descendants("Library")
                .FirstOrDefault(e=>e.Attribute("Name").Value=="Main")
                .Descendants("ReadingList").Where(t=>t.Attribute("Name").Value=="Test2"));

你在找这样的东西吗?

        var table = XElement.Parse(@"<app>
                                        <Library Name=""Main"" Path=""C:'somefile.Xml"">
                                            <ReadingList Name=""Test1"">
                                                <Book>Book1</Book>
                                            </ReadingList>
                                            <ReadingList Name=""Test2"">
                                                <Book>Book2</Book>
                                            </ReadingList>
                                        </Library>
                                        <Library Name=""Backup"" Path=""C:'somefile.Xml""></Library>
                                    </app>");

        var readingList = table
            .Elements("Library")
            .FirstOrDefault(x => x.Attribute("Name")?.Value == "Main")
            .Elements("ReadingList")
            .FirstOrDefault(x => x.Attribute("Name")?.Value == "Test2");

这将从本质上解决您的查询,即获得名为Test2ReadingList和名为Test 1ReadingList

您可以选择Where而不是FirstOrDefault,但这将以所有可能匹配的列表结束。

        var readingList = table
            .Elements("Library")
            .Where(x => x.Attribute("Name").Value == "Main")
            .Elements("ReadingList")
            .Where(x => x.Attribute("Name").Value == "Test2")
            .ToList(); 

选择后代变体当然会减少查找。

        var readingList = table
            .Descendants("Library")
            .Where(x => x.Attribute("Name").Value == "Main")
            .Descendants("ReadingList")
            .Where(x => x.Attribute("Name").Value == "Test2")
            .ToList();