Показаны сообщения с ярлыком Xml. Показать все сообщения
Показаны сообщения с ярлыком Xml. Показать все сообщения

среда, 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)));

среда, 6 октября 2010 г.

XDocument. Работа с элементами без явного указания пространства имен по умолчанию (Default Namespace)

Если вы используете XDocument, Xml которого содержит явное пространство имен по умолчанию, то во время разбора элементов придется его явно указывать. Для ясности кусочки кода:
<Data xmlns="http://selo-blog.blogspot.com/">
 <Name>Иван</Name>
 <Gender>мужской</Gender>
</Data>

Чтобы получить значение тега "Name", придется выполнить следующий код:
XDocument xDoc = XDocument.Parse(inputString);
XNamespace xSpace = "http://selo-blog.blogspot.com/";
String name = xDoc.Root.Element(xSpace + "Name").Value;

Немного раздражительно, не правда ли?

Для облегчения страданий я создал следующие методы-расширения
public static class Extensions {
  public static XElement xElement(this XElement xParent, String name) {
    return xParent.Element(xParent.Name.Namespace + name);
  }

  public static IEnumerable<XElement> xElements(this XElement xParent, String name) {
    return xParent.Elements(xParent.Name.Namespace + name);
  }
}

Теперь работа с документом происходит обычным способом:
String name = xDoc.Root.xElement("Name").Value;

* This source code was highlighted with Source Code Highlighter.

вторник, 11 мая 2010 г.

XDocument в XMLDocument и наоборот

У меня в примерах
XmlDocument xmlDoc;
XDocument xDoc;

XMLDocument To XMLDocument

Самый простой, но и пожалуй самый медленный способ:
XDocument.Parse(xmlDoc.OuterXml);

Второй вариант:
using (var nodeReader = new XmlNodeReader(xmlDoc)) {
nodeReader.MoveToContent();
xDoc = XDocument.Load(nodeReader);
}

XMLDocument To XMLDocument

Очень простой способ:
xmlDoc.Load(xDoc.CreateReader());

И чего это я раньше следующим монстром пользовался?
using (MemoryStream memStr = new MemoryStream()) {
using (XmlWriter writer = XmlWriter.Create(memStr)) {
xDoc.Save(writer);
}
memStr.Position = 0;
using (XmlReader reader = XmlReader.Create(memStr)) {
xmlDoc.Load(reader);
}
}