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
В данный момент, наш файл содержит следующую структуру:
Взаимоотношение между узлами в XML DOM, основные моменты:
1. Любой узел в DOM дереве имеет родителя ParentNode. В нашем примере garage является родителем для обоих элементов car, а оба элемента car, являются в свою очередь родителями для элементов: model и year.
Как получить родителя для xml элемента car?
Console.WriteLine(elmRoot["car"].ParentNode.Name); //Результат: garage
2. У родителя могут быть дети ChildNodes. Например, для узла garage детьми являются оба элемента car. У элементов car, тоже есть дети model и year.
ChildNodes, представляет собой коллекцию, которая хранит все дочерние xml элементы, чтобы обратиться к нужному элементу, нужно указать его индекс. (Индекс всегда начинается с нуля!)
Например: как получить первый дочерний элемент?
elmRoot.ChildNodes[0];
3. Как и в обычной жизни ребенок может родиться первым FirstChild, или последним LastChild.
Если взять для примера элемент car, то
FirstChild - это model LastChild - это year
4. В свою очередь между дочерними элементами тоже существуют связи, они могут быть братьями или сестрами, если проводить параллели с реальной жизнью.
У ребенка может быть к примеру брат 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 является NextSibling;
FirstChild является PreviousSibling;
С помощью выше описанных методов можно легко переместиться к нужному узлу и получить любое нужное вам значение.
Как получить значение xml элемента?
Значение xml элемента можно получить при помощи свойства InnerText, например:
Console.WriteLine(elmRoot["car"].FirstChild.InnerText); //Результат: mazda
Ещё один способ, чтобы получить это же значение xml элемента:
Console.WriteLine(elmRoot.FirstChild.FirstChild.InnerText); //Результат: mazda
Последовательность перемещений по DOM дереву:
garage -> car -> model -> Мазда
Получаем год:
elmRoot["car"].LastChild.InnerText; //Результат: 2007
Последовательность:
garage -> car -> year -> 2007
Ещё пример: 3 способа, для получения одного и того же результата.
Console.WriteLine(elmRoot.LastChild.FirstChild.InnerText); Console.WriteLine(elmRoot["car"].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 = "2010"; //Выводим новое значение на экран консоли Console.WriteLine(elmRoot.FirstChild.ChildNodes.Item(1).InnerText); //Результат: 2010
При этом нужно помнить, что все изменения происходят с виртуальным xml файлом, если Вы откроете физический файл, то увидите, что по-прежнему в нём указан год 2007.
Для того, чтобы изменения вступили в силу, нужно воспользоваться методом Save, например:
elmRoot.Save("имя xml файла или поток");
Теперь информация будет изменена в «физическом» 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("bus");
Создание и добавление нового xml элемента
Создадим новый xml элемент по имени «BUS».
XmlElement elmRoot = xmlDoc.DocumentElement; Console.WriteLine(elmRoot.ChildNodes.Count); //car, car XmlElement elmNew = xmlDoc.CreateElement("bus"); 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 = @"C:\lessons\Auto.xml"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(strFilename); XmlElement elmRoot = xmlDoc.DocumentElement; XmlElement elmNew = xmlDoc.CreateElement("bus"); XmlText new_txt = xmlDoc.CreateTextNode("2006"); 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>
Для наглядности
А теперь создадим узел «bus», с такой же архитектурой, как и car, то есть добавим узлы: model, year и какое-нибудь текстовое содержимое.
Создание XML элемента с дочерними элементами
string strFilename = @"C:\lessons\Auto.xml"; //создаем новый xml документ в памяти XmlDocument xmlDoc = new XmlDocument(); //загружаем xml файл в память xmlDoc.Load(strFilename); //Получаем root-элемент XmlElement elmRoot = xmlDoc.DocumentElement; //Создаём 3 элемента: bus, model, year XmlElement elmBUS = xmlDoc.CreateElement("bus"); XmlElement elmModel = xmlDoc.CreateElement("model"); XmlElement elmYear = xmlDoc.CreateElement("year"); //Устанавливаем значения для элементов: model, year XmlText year_txt = xmlDoc.CreateTextNode("2006"); //XmlText mod_txt = xmlDoc.CreateTextNode("liaz"); добавим иначе //К элементу bus добавляем два дочерних элемента: model и year elmBUS.AppendChild(elmModel); elmBUS.AppendChild(elmYear); //Добавляем значения узлам model и year elmModel.InnerText = "liaz"; 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 = @"C:\lessons\Auto.xml"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(PathXmlFile); XmlElement elmRoot = xmlDoc.DocumentElement; XmlElement elmBUS = xmlDoc.CreateElement("bus"); XmlElement elmModel = xmlDoc.CreateElement("model"); XmlElement elmYear = xmlDoc.CreateElement("year"); //Добавляем значения узлам model и year elmModel.InnerText = "liaz"; elmYear.InnerText = "2006"; 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("bus"); string txt = "<model>liaz</model>" + "<year>2006</year>"; //InnerXml! elmXML.InnerXml = txt; //xmlDoc.DocumentElement (будет равен garage) - это ещё один способ обратиться к root-элементу, тоже самое что и XmlElement elmRoot = xmlDoc.DocumentElement; xmlDoc.DocumentElement.AppendChild(elmXML); xmlDoc.Save(PathXmlFile);
Результат
Получить список элементов при помощи GetElementByTagName
GetElementByTagName возвращает XmlNodeList, в котором содержаться все элементы потомки, принадлежащие указному элементу, например, нам нужно получить все модели машин, которые хранятся в гараже:
XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(strFilename); XmlNodeList modelName = xmlDoc.GetElementsByTagName("model"); foreach (XmlNode node in modelName) { Console.WriteLine(node.InnerText); } //Результат: mazda, bmw, liaz
Обращение при помощи индекса:
string PathXmlFile = @"C:\lessons\Auto.xml"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(PathXmlFile); XmlNodeList modelName = xmlDoc.GetElementsByTagName("model"); Console.WriteLine(modelName[2].InnerText); //Результат: liaz
Как изменить текстовое содержимое, у только что созданного элемента «bus», при помощи метода GetElementByTagName?
string PathXmlFile = @"C:\lessons\Auto.xml"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(PathXmlFile); XmlNodeList modelName = xmlDoc.GetElementsByTagName("model"); Console.WriteLine(modelName[2].InnerText); //Получили значение: liaz
Либо можно изменить имя liaz на Ikarus
Console.WriteLine(modelName[2].InnerText = "Ikarus");
Читайте также: