среда, 22 июня 2016 г.

Получение значения вложенного XElement-а.

[Getting the value of a nested XElement]

Допустим у нас есть следующий документ:

XDocument xDoc = XDocument.Parse(@"<Data> <X> <Y> <Z>Здесь!</Z> </Y> </X> </Data>");

Получение значения XElementa  „Z“ достаточно тривиальная задача:

String value = xDoc.Root.Element("X").Element("Y").Element("Z").Value;

Но задача усложняется, если нужно значение одного из вложенных элементов где цепочка вложенности узлов, хоть и известна, но может обрываться в любом месте. Тогда понадобится проверять каждый из под-узлов на существование.  
Получается очень громоздко.

Что бы получить значение «в один вызов», можно воспользоваться методами расширениями:

public static String xValueOrNull (this XElement xEl) {
if (xEl == null) return null;
else return xEl.Value;
}
public static XElement xElementOrNull(this XElement root, String elemName) {
if (root == null) return null;
return root.Element(elemName);
}  
Тогда вызов будет примерно таким:

String val = xDoc.Root.xElementOrNull("X").xElementOrNull("Y").xElementOrNull("Z").xValueOrNull();

Недостатком такого способа является то, что если в самом начале цепочки узел не существует, проверка все равно продолжится и для следующих узлов.
Другим решением может быть использование вспомогательных методов расширений, которые бы обрывали вызов, например такого:

public static String xFuncValueOrNull(this XElement xEl, String elemName, Func<XElement, String> func) {
if (xEl == null) return null;
XElement subEl = xEl.Element(elemName);
if (subEl == null) return null;
return func(subEl);
}

И вызов:

String val = xDoc.Root.xFuncValueOrNull("X", x => x.xFuncValueOrNull("Y", y => y.xFuncValueOrNull("Z", z => x.Value)));