[英]C# find xml element matching two element levels using linq
I am trying to select an XElement from an xml document and match on two "levels" of the xml document. 我试图从xml文档中选择一个XElement并匹配xml文档的两个“级别”。 my file structure is:
我的文件结构是:
<app>
<Library Name="Main" Path="C:\somefile.Xml">
<ReadingList Name="Test1">
<Book>...
<ReadingList Name="Test2">
<Book>...
<Library Name="Backup" Path="C:\somefile.Xml">
And I want to find the reading list name "test2" in library "Main" so I can copy this element and all child elements to another Library node. 我想在库“Main”中找到读取列表名称“test2”,因此我可以将此元素和所有子元素复制到另一个Library节点。
I would prefer a solution using linq as I am trying to learn this. 我更喜欢使用linq的解决方案,因为我正在尝试学习这个。
Thanks in advance for any help 在此先感谢您的帮助
When I add a new "reading list" I do it this way: 当我添加一个新的“阅读列表”时,我这样做:
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);
}
but the operation I want to perform is a copy of this element and sub elements. 但我想要执行的操作是此元素和子元素的副本。 The problem is, there may be more than one "library" element with the same name so I need to check the library name and reading list name.
问题是,可能有多个具有相同名称的“库”元素,因此我需要检查库名称和读取列表名称。 does that make sense?
那有意义吗?
Using a combination of .Descendants
and Where
s will do the trick: 使用
.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();
You can also use .Elements
instead of Descendants
I just preferred to use it so to not specify also the level of app
or any other along the way. 你也可以使用
.Elements
而不是Descendants
我只是喜欢使用它,所以不要指定app
的级别或其他任何方式。
For prior c# 6.0 you can do: 对于之前的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();
Or if creating a method to help with it instead of repeating the code: 或者,如果创建一个方法来帮助它而不是重复代码:
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();
Are you looking for something like this? 你在找这样的东西吗?
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");
This would essentially solve your query of getting a ReadingList
that is named Test2
and under a ReadingList
named Test 1
. 这将从根本上解决你获得的查询
ReadingList
名为Test2
和下ReadingList
名为Test 1
。
You can opt for Where
instead of FirstOrDefault
but that would end up with a list of all possible matches. 您可以选择
Where
而不是FirstOrDefault
但最终会得到所有可能匹配的列表。
var readingList = table
.Elements("Library")
.Where(x => x.Attribute("Name").Value == "Main")
.Elements("ReadingList")
.Where(x => x.Attribute("Name").Value == "Test2")
.ToList();
Opting for a descendant variant would end up in lesser lookup of course. 选择后代变体会导致较少的查找。
var readingList = table
.Descendants("Library")
.Where(x => x.Attribute("Name").Value == "Main")
.Descendants("ReadingList")
.Where(x => x.Attribute("Name").Value == "Test2")
.ToList();
You can also do this query: 您也可以执行以下查询:
var query= xdoc.Descendants("Library")
.Where(e=>e.Attribute("Name").Value=="Main")
.SelectMany(e=>e.Elements("ReadingList").Where(t=>t.Attribute("Name").Value=="Test2"));
If there are just one Main
element you can also use FirstOrDefault
extension method: 如果只有一个
Main
元素,您还可以使用FirstOrDefault
扩展方法:
var query= xdoc.Descendants("Library")
.FirstOrDefault(e=>e.Attribute("Name").Value=="Main")
.Descendants("ReadingList").Where(t=>t.Attribute("Name").Value=="Test2"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.