我有一个类似于以下结构的 XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<Root Attr1="Foo" Name="MyName" Attr2="Bar" >
<Parent1 Name="IS">
<Child1 Name="Kronos1">
<GrandChild1 Name="Word_1"/>
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child1>
<Child2 Name="Kronos2">
<GrandChild1 Name="Word_1"/>
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child2>
</Parent1>
</Root>
元素未定义,因为它们可以具有与其他文件不同的值。我所知道的是手头每个元素的“名称”属性,它将始终被定义。我需要能够根据该名称操作和/或删除所选元素中的数据。例如:removeElement("MyName.IS.Kronos1.Word_1")
将删除 Child1
父项下的 GrandChild1
元素。
我的问题是,在使用 LINQ to XML 查询时,我无法正确选择该元素。使用这个:
private IEnumerable<XElement> findElements(IEnumerable<XElement> docElements, string[] names)
{
// the string[] is an array from the desired element to be removed.
// i.e. My.Name.IS ==> array[ "My, "Name", "IS"]
IEnumerable<XElement> currentSelection = docElements.Descendants();
foreach (string name in names)
{
currentSelection =
from el in currentSelection
where el.Attribute("Name").Value == name
select el;
}
return currentSelection;
}
要找到我需要删除元素的位置会产生以下结果:
<?xml version="1.0" encoding="utf-8"?>
<Root Attr1="Foo" Name="MyName" Attr2="Bar" >
<Parent1 Name="IS">
<Child1 Name="Kronos1">
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child1>
<Child2 Name="Kronos2">
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child2>
</Parent1>
</Root>
调试后,似乎我所做的只是再次搜索同一个文档,但每次搜索的名称不同。如何根据多个父属性名称搜索和选择特定元素?
应注意,XML 的大小(表示元素的级别)也是可变的。这意味着可以有少至 2 个级别( parent )或最多 6 个级别(曾孙)。但是,我还需要能够查看根节点的 Name
属性。
最佳答案
这应该有效:
if (doc.Root.Attribute("Name").Value != names.First())
throw new InvalidOperationException("Sequence contains no matching element.");
var selection = doc.Root;
foreach (var next in names.Skip(1))
selection = selection.Elements().First(x => x.Attribute("Name").Value == next);
return selection;
如果您愿意,可以用以下内容替换最新的行:
var selection = names.Skip(1).Aggregate(doc.Root, (current, next) => current.Elements().First(x => x.Attribute("Name").Value == next));
如果在源中找不到匹配的元素,.First()
方法会抛出异常。
最干净的方法是添加一个新函数:
XElement SelectChildElement(XElement current, string child)
{
if (current == null)
return null;
var elements = current.Elements();
return elements.FirstOrDefault(x => x.Attribute("Name").Value == child);
}
这样你就可以简单地使用它如下:
if (doc.Root.Attribute("Name").Value != names.First())
return null;
return names.Skip(1).Aggregate(doc.Root, SelectChildElement);
然后,如果您需要选择一个 child ,您可以使用方便的 SelectChildElement()
方法。如果您想改为执行 myElement.SelectChild(child)
,您可以从 extension 中调用它.
此外,当您在此处使用 FirstOrDefault 时,您不会得到异常,而是返回 null
。
这样,它就不必跟踪通常代价更高的异常......
关于c# - 如何根据多个父元素的属性删除子元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10889071/