我正在尝试从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”,因此我可以将此元素和所有子元素复制到另一个Library节点。
我更喜欢使用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);
}
但我想要执行的操作是此元素和子元素的副本。问题是,可能有多个具有相同名称的“库”元素,因此我需要检查库名称和读取列表名称。那有意义吗?
答案 0 :(得分:2)
使用.Descendants
和Where
的组合可以解决问题:
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();
答案 1 :(得分:0)
你在找这样的东西吗?
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");
这基本上可以解决您在名为ReadingList
的{{1}}下Test2
获取名为ReadingList
的{{1}}的问题。
您可以选择Test 1
代替Where
,但最终会列出所有可能的匹配项。
FirstOrDefault
选择后代变体会导致较少的查找。
var readingList = table
.Elements("Library")
.Where(x => x.Attribute("Name").Value == "Main")
.Elements("ReadingList")
.Where(x => x.Attribute("Name").Value == "Test2")
.ToList();
答案 2 :(得分:0)
您也可以执行此查询:
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"));