Мне нужно выражение LINQ, чтобы найти XElement, где имя элемента и атрибуты соответствуют входному узлу
-
03-07-2019 - |
Вопрос
Мне нужно заменить содержимое узла в иерархии XElement, когда имя элемента и все имена атрибутов и значения соответствуют входному элементу.(Если совпадения нет, можно добавить новый элемент.)
Например, если мои данные выглядят следующим образом:
<root>
<thing1 a1="a" a2="b">one</thing1>
<thing2 a1="a" a2="a">two</thing2>
<thing2 a1="a" a3="b">three</thing2>
<thing2 a1="a">four</thing2>
<thing2 a1="a" a2="b">five</thing2>
<root>
Я хочу найти последний элемент, когда я вызываю метод с этим вводом:
<thing2 a1="a" a2="b">new value</thing2>
Метод не должен иметь жестко закодированных имен элементов или атрибутов - он просто сопоставляет входные данные с данными.
Решение
Это будет соответствовать любому заданному элементу с точными парами имя тега и имя атрибута / значение:
public static void ReplaceOrAdd(this XElement source, XElement node)
{
var q = from x in source.Elements()
where x.Name == node.Name
&& x.Attributes().All(a =>node.Attributes().Any(b =>a.Name==b.Name && a.Value==b.Value))
select x;
var n = q.LastOrDefault();
if (n == null) source.Add(node);
else n.ReplaceWith(node);
}
var root = XElement.Parse(data);
var newElem =XElement.Parse("<thing2 a1=\"a\" a2=\"b\">new value</thing2>");
root.ReplaceOrAdd(newElem);
Другие советы
Вы можете создать XPathSelectElement с указанием пути (не цитируйте меня, я был в баре;уберу утром) /root/thing2[@a1='a' и @a2='b'], а затем заберу .LastOrDefault() (XPathSelectElement - это метод расширения в system.Linq.Xml).
Это даст вам узел, который вы хотите изменить.Однако я не уверен, как вы хотите это изменить.Результат, который вы получаете, является фактическим XElement, поэтому его изменение приведет к изменению элемента дерева.