Работа с xml файлами

XML DOM 2

В предыдущей статье были описаны общие понятия касающиеся XML. В этой статье научимся выполнять основные действия, связанные с изменением, добавлением, поиском в XML файле.

XML файл, который используется для примера.

<garage>
<car>
<model>Mazda</model>
<year>2007</year>
</car>
<car>
<model>BMW</model>
<year>2009</year>
</car>
</garage>

xml dom

В данный момент, наш файл содержит следующую структуру:

dom

DOM

Взаимоотношение между узлами в XML DOM, основные моменты:

1. Любой узел в DOM дереве имеет родителя ParentNode. В нашем примере garage является родителем для обоих элементов car, а оба элемента car, являются в свою очередь родителями для элементов: model и year.

Как получить родителя для xml элемента car?

Console.WriteLine(elmRoot[&#034;car&#034;].ParentNode.Name); 
//Результат: garage

2. У родителя могут быть дети ChildNodes. Например, для узла garage детьми являются оба элемента car. У элементов car, тоже есть дети &#8212; model и year.

ChildNodes, представляет собой коллекцию, которая хранит все дочерние xml элементы, чтобы обратиться к нужному элементу, нужно указать его индекс. (Индекс всегда начинается с нуля!)

Например: как получить первый дочерний элемент?

elmRoot.ChildNodes[0];

3. Как и в обычной жизни ребенок может родиться первым FirstChild, или последним LastChild.

Если взять для примера элемент car, то

FirstChild - это model
LastChild  - это year

4. В свою очередь между дочерними элементами тоже существуют связи, они могут быть братьями или сестрами, если проводить параллели с реальной жизнью.

У ребенка может быть к примеру брат &#8212; Previous Sibling и следующий брат Next Sibling

Console.WriteLine(elmRoot.ChildNodes[0].FirstChild.NextSibling.Name);
//Результат: year
Console.WriteLine(elmRoot.ChildNodes[0].
LastChild.PreviousSibling.Name);
//Результат: model

Если элемент не найден, то тогда возникает исключение: NullReferenceException, поэтому при работе с xml всегда используйте блоки try catch.

Console.WriteLine(elmRoot.ChildNodes[0].
LastChild.NextSibling.Name);
Console.WriteLine(elmRoot.ChildNodes[0].
FirstChild.PreviousSibling.Name);

LastChild &#8212; является NextSibling;
FirstChild &#8212; является PreviousSibling;

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

Как получить значение xml элемента?

Значение xml элемента можно получить при помощи свойства InnerText, например:

Console.WriteLine(elmRoot[&#034;car&#034;].FirstChild.InnerText);
//Результат: mazda

Ещё один способ, чтобы получить это же значение xml элемента:

Console.WriteLine(elmRoot.FirstChild.FirstChild.InnerText);
//Результат: mazda

Последовательность перемещений по DOM дереву:

garage -> car -> model -> Мазда

Получаем год:

elmRoot[&#034;car&#034;].LastChild.InnerText;
//Результат: 2007

Последовательность:

garage -> car -> year -> 2007

Ещё пример: 3 способа, для получения одного и того же результата.

Console.WriteLine(elmRoot.LastChild.FirstChild.InnerText);
Console.WriteLine(elmRoot[&#034;car&#034;].NextSibling.FirstChild.InnerText);
Console.WriteLine(elmRoot.ChildNodes.Item(1).FirstChild.InnerText);
//Результат: BMW

Если надо получить год для элемента со значением Mazda:

Console.WriteLine(elmRoot.FirstChild.LastChild.InnerText);
//Результат: 2007

Для BMW (два способа, получить один и тот же результат)

Console.WriteLine(elmRoot.ChildNodes.Item(1).
ChildNodes.Item(1).InnerText);
Console.WriteLine(elmRoot.ChildNodes[1].ChildNodes[1].InnerText);
//Результат: 2009

Как изменить значения xml элемента?

С помощью свойства InnerText() можно, как получить, так и изменить значение xml элемента, например изменим год.

//Устанавливаем новое значение
elmRoot.FirstChild.LastChild.InnerText = &#034;2010&#034;;
//Выводим новое значение на экран консоли 
Console.WriteLine(elmRoot.FirstChild.ChildNodes.Item(1).InnerText);
//Результат: 2010

При этом нужно помнить, что все изменения происходят с виртуальным xml файлом, если Вы откроете физический файл, то увидите, что по-прежнему в нём указан год 2007.

Для того, чтобы изменения вступили в силу, нужно воспользоваться методом Save, например:

elmRoot.Save("имя xml файла или поток");

Теперь информация будет изменена в &#171;физическом&#187; xml файле.

Как получить количество дочерних элементов?

Console.WriteLine(elmRoot.FirstChild.ChildNodes.Count);

garage -> car содержит 2 ребенка: model и year

Console.WriteLine(elmRoot.FirstChild.FirstChild.ChildNodes.Count);

garage -> car -> model содержит 1 дочерний xml элемент.

Обращение к дочерним элементам

по индексу

elmRoot.ChildNodes[0].Name;
elmRoot.ChildNodes[1].Name;
//Результат: car

С помощью цикла

foreach (XmlNode nod in elmRoot.ChildNodes)
{
Console.WriteLine(nod.Name);
}
//Результат: car, car

Как получить имя xml элемента?

elmRoot.Name;
//Результат: garage

Создание нового XML элемента

Создадим новый элемент в нашем XML документе, чтобы он отличался от двух других (car) назовём его автобус (bus).

При создании нового элемента воспользуемся рекомендацией с сайта msdn и вместо стандартного new XmlElement воспользуемся методом CreateElement.

XmlElement elm = xmlDoc.CreateElement(&#034;bus&#034;);

Создание и добавление нового xml элемента

Создадим новый xml элемент по имени &#171;BUS&#187;.

XmlElement elmRoot = xmlDoc.DocumentElement;
Console.WriteLine(elmRoot.ChildNodes.Count);
//car, car
XmlElement elmNew = xmlDoc.CreateElement(&#034;bus&#034;);
elmRoot.AppendChild(elmNew);
Console.WriteLine(elmRoot.ChildNodes.Count); 
//3 car, car, bus
xmlDoc.Save("имя xml файла");

Пояснение:

1. Сначала получаем root-элемент к которому будем крепить новые элементы.

2. В качестве проверки выведем текущее количество дочерних элементов у элемента garage: 2 (car и car)

3. Создаем новый элемент BUS

4. При помощи метода AppendChild добавляем новый элемент в дерево

5. Снова воспользуемся проверкой и выведем текущее количество элементов у элемента garage, теперь их стало 3: car, car, bus.

6. Чтобы изменения затронули физический файл, сохраняемся

В самом XML файле новый элемент будет выглядеть так:

<bus/>

Как добавить новый xml элемент?

Задача: создать новый XML элемент и добавить в него какое-нибудь текстовое содержимое, например год выпуска.

string strFilename = @&#034;C:\lessons\Auto.xml&#034;;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(strFilename);
XmlElement elmRoot = xmlDoc.DocumentElement;
XmlElement elmNew = xmlDoc.CreateElement(&#034;bus&#034;);
XmlText new_txt = xmlDoc.CreateTextNode(&#034;2006&#034;);
elmRoot.AppendChild(elmNew);
elmRoot.LastChild.AppendChild(new_txt);
Console.WriteLine(elmRoot.ChildNodes[2].Name); //bus
Console.WriteLine(elmRoot.ChildNodes[2].LastChild.InnerText); //2006
Console.Read();

В XML файле:

<bus>2006</bus>

Для наглядности

Добавление нового XML элемента

А теперь создадим узел &#171;bus&#187;, с такой же архитектурой, как и car, то есть добавим узлы: model, year и какое-нибудь текстовое содержимое.

Создание XML элемента с дочерними элементами

string strFilename = @&#034;C:\lessons\Auto.xml&#034;;
//создаем новый xml документ в памяти
XmlDocument xmlDoc = new XmlDocument();
//загружаем xml файл в память
xmlDoc.Load(strFilename);
//Получаем root-элемент
XmlElement elmRoot = xmlDoc.DocumentElement;
//Создаём 3 элемента: bus, model, year
XmlElement elmBUS = xmlDoc.CreateElement(&#034;bus&#034;);
XmlElement elmModel = xmlDoc.CreateElement(&#034;model&#034;);
XmlElement elmYear = xmlDoc.CreateElement(&#034;year&#034;);
//Устанавливаем значения для элементов: model, year
XmlText year_txt = xmlDoc.CreateTextNode(&#034;2006&#034;);
//XmlText mod_txt = xmlDoc.CreateTextNode(&#034;liaz&#034;); добавим иначе
//К элементу bus добавляем два дочерних элемента: model и year
elmBUS.AppendChild(elmModel);
elmBUS.AppendChild(elmYear);
//Добавляем значения узлам model и year
elmModel.InnerText = &#034;liaz&#034;;
elmYear.AppendChild(year_txt);
//Добавляем в дерево новый xml элемент bus
elmRoot.AppendChild(elmBUS);
//Проверяем, всё ли добавлено, как надо
Console.WriteLine(elmRoot.ChildNodes[2].FirstChild.InnerText);
Console.WriteLine(elmRoot.LastChild.LastChild.InnerText);
//Если всё в порядке, то используем метод Save
xmlDoc.Save("имя xml файла");

Результат:

<bus>
<model>liaz</model>
<year>2006</year>
</bus>

Как можно сократить, данный код? Например, следующим образом:

string PathXmlFile = @&#034;C:\lessons\Auto.xml&#034;;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(PathXmlFile);
XmlElement elmRoot = xmlDoc.DocumentElement;
XmlElement elmBUS = xmlDoc.CreateElement(&#034;bus&#034;);
XmlElement elmModel = xmlDoc.CreateElement(&#034;model&#034;);
XmlElement elmYear = xmlDoc.CreateElement(&#034;year&#034;);
//Добавляем значения узлам model и year
elmModel.InnerText = &#034;liaz&#034;;
elmYear.InnerText = &#034;2006&#034;;
elmBUS.AppendChild(elmModel);
elmBUS.AppendChild(elmYear);
elmRoot.AppendChild(elmBUS);
//Если всё верно, то вызываем метод Save
xmlDoc.Save("имя xml файла");

Ещё немного сократим код, для этого воспользуемся свойством InnerXml:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(PathXmlFile);
XmlElement elmXML = xmlDoc.CreateElement(&#034;bus&#034;);
string txt = "<model>liaz</model>&#034; + "<year>2006</year>&#034;;
//InnerXml!
elmXML.InnerXml = txt;
//xmlDoc.DocumentElement (будет равен garage) -
это ещё один способ обратиться к root-элементу, тоже самое что и
XmlElement elmRoot = xmlDoc.DocumentElement;
xmlDoc.DocumentElement.AppendChild(elmXML);
xmlDoc.Save(PathXmlFile);

Результат

Создание XML элемента

Получить список элементов при помощи GetElementByTagName

GetElementByTagName возвращает XmlNodeList, в котором содержаться все элементы потомки, принадлежащие указному элементу, например, нам нужно получить все модели машин, которые хранятся в гараже:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(strFilename);
XmlNodeList modelName = xmlDoc.GetElementsByTagName(&#034;model&#034;);
foreach (XmlNode node in modelName)
{
Console.WriteLine(node.InnerText);
}
//Результат: mazda, bmw, liaz

Обращение при помощи индекса:

string PathXmlFile = @&#034;C:\lessons\Auto.xml&#034;;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(PathXmlFile);
XmlNodeList modelName = xmlDoc.GetElementsByTagName(&#034;model&#034;);
Console.WriteLine(modelName[2].InnerText);
//Результат: liaz

Как изменить текстовое содержимое, у только что созданного элемента &#171;bus&#187;, при помощи метода GetElementByTagName?

string PathXmlFile = @&#034;C:\lessons\Auto.xml&#034;;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(PathXmlFile);
XmlNodeList modelName = xmlDoc.GetElementsByTagName(&#034;model&#034;);
Console.WriteLine(modelName[2].InnerText);
//Получили значение: liaz

Либо можно изменить имя liaz на Ikarus

Console.WriteLine(modelName[2].InnerText = &#034;Ikarus&#034;);

Читайте также:

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*