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"元素具有相同的名称,所以我需要检查图书馆名称和阅读列表名称。明白了吗?
使用.Descendants
和Where
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");
这将从本质上解决您的查询,即获得名为Test2
的ReadingList
和名为Test 1
的ReadingList
。
您可以选择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();