LINQ, Зміна даних у XML

Завдяки LINQ to XML, модифікація даних XML тепер стала простішою, ніж будь-коли раніше. Оперуючи лише невеликим набором методів, можна виконувати будь-які бажані модифікації. Будь то додавання, зміна або видалення вузлів або елементів завжди знайдеться метод, який може виконати роботу.

Як неодноразово повторювалося, в LINQ to XML більшість часу посідає роботу з об'єктами XElement. Тому більшість наведених прикладів пов'язані з обробкою елементів. Класи LINQ to XML, успадковані від XNode, розглядаються першими, а за ними слідує розділ, присвячений атрибутам.

Додавання вузлів

Цей розділ, присвячений додаванню нових вузлів до дерева XML, починається з базового прикладу коду, наведеного нижче:

Цей код виробляє дерево XML із єдиним співробітником. Ось його висновок:

Опис різних методів додавання вузлів розпочинається з цього базового коду.

Хоча до всіх наступних прикладів додаються елементи, той самий прийом працює з усіма класами LINQ to XML, успадкованими від XNode.

На додаток до таких способів додавання вузлів не забудьте заглянути в розділ "Виклик XElement.SetElementValue() на дочірніх об'єктах XElement" далі в цій статті.

XContainer.Add() (AddLast)

Метод, який буде використовуватися найчастіше для додавання елементів у дерево XML – це Add. Він додає вузол до кінця списку дочірніх вузлів по відношенню до зазначеного вузла. Нижче наведено приклад:

У цьому коді видно, що базовий код доповнений кодом додавання елемента Employee до елемента документа Employees. Тут за допомогою методу Element документа виходить елемент Employees, після чого з використанням методу Add до списку його дочірніхелементів додається новий елемент. Нижче показано результат:

зміна

Метод Add додає знову сконструйований елемент Employee до кінця списку дочірніх вузлів елемента Employees. Як бачите, метод Add такий же гнучкий, як і конструктор XElement, і дотримується тих же правил щодо аргументів, що дозволяє застосовувати функціональне конструювання.

XContainer.AddFirst()

Додавання вузла на початок списку дочірніх вузлів служить метод AddFirst. Взявши за основу той же код, що й раніше, за винятком виклику методу Add, отримаємо код, наведений нижче:

Як і можна було очікувати, доданий елемент Employee з'явиться в голові списку дочірніх вузлів елемента Employees:

зміна

Чи можна уявити простий спосіб маніпуляцій XML? Навряд чи.

XNode.AddBeforeSelf() та XNode.AddAfterSelf

Щоб вставити вузол у певне місце всередині списку дочірніх вузлів, необхідно отримати посилання або на попередній вузол, або на вузол, що безпосередньо слідує за місцем вставки, і викликати метод AddBeforeSelf або AddAfterSelf.

Як відправна точка використовується дерево XML, вироблене прикладом методу Add. У це дерево буде вставлено новий вузол між двома існуючими елементами Employee:

linq

Щоб освіжити в пам'яті опис стандартних операцій запитів, що давався в розділі LINQ to Objects, і для інтеграції цих відомостей із матеріалом, розглянутим у цій статті, елемент Employee, перед яким має бути вставлений новий, шукається за допомогою арсеналу операцій LINQ.

За допомогою методу Element робиться поглиблення в документ для вибору елемента Employees. Потім вибираються дочірні елементи Employees з ім'ям Employee, які мають дочірній елемент поімені FirstName зі значенням "Elena". Оскільки відомо, що цьому критерію відповідає лише один елемент Employee і тому, що необхідний об'єкт типу XElement, на якому можна викликати метод AddBeforeSelf, викликається операція Single для отримання об'єкта Employee типу XElement. Це дає посилання на Employee, перед яким потрібно вставити новий XElement.

Також зверніть увагу, що у виклику операції Where виконується приведення елемента FirstName до string для використання засобу отримання значення вузла. Це дозволяє отримати значення елемента FirstName з його порівняння з " Elena " .

Маючи посилання на правильний елемент Employee, можна просто викликати метод AddBeforeSelf. Ось результат:

даних

Як і потрібно, новий елемент Employee вставлений перед елементом Employee, у якого значення елемента FirstName дорівнює "Elena".

Порівняно з попереднім цей приклад видасться тривіальним.

Видалення вузлів

Видалення вузлів виконується за допомогою одного із двох методів: Remove або RemoveAll.

XNode.Remove()

Якщо все правильно, то має бути отримане дерево XML спочатку з першим елементом, що описує співробітника, а потім без нього:

linq

Як бачите, перший елемент Employee зник у результаті видалення.

IEnumerable .Remove()

У попередньому випадку метод Remove викликався на єдиному об'єкті XElement. Однак його можна також викликати на послідовності (IEnumerable). Нижче наведено приклад, у якому за допомогою методу Descendants документа здійснюється рекурсивний обхід униз дерева XML з поверненням лише елементів з ім'ям FirstName, для чого використовується операція Where. Потім на результуючій послідовності викликається метод Remove:

Цей приклад цікавий тим,що можна зв'язати разом всі елементи LINQ. За допомогою методу XDocument.Descendants витягуються у вигляді послідовності всі дочірні вузли, а потім викликається стандартна операція запиту Where для фільтрації лише вузлів, які відповідають критерію пошуку, яким в даному випадку є ім'я FirstName. Вона повертає послідовність, де потім викликається метод Remove. Нижче показано результат:

XElement.RemoveAll()

Іноді потрібно видалити вміст елемента, але не сам елемент. Саме для цього призначений метод RemoveAll. Нижче наведено приклад:

Перш ніж видалити вміст вузла Employees, у коді спочатку відображається документ. Потім вміст вузла Employees видаляється, і документ з'являється знову. Ось як виглядає результат:

linq

Оновлення вузлів

XElement.Value на об'єктах XElement, XText.Value на об'єктах XText та XComment.Value на об'єктах XComment

Кожен із цих підкласів XNode має властивість Value, яка може бути встановлена ​​для оновлення значення вузла. Усі вони продемонстровані нижче:

даних

Як бачите, всі значення вузлів оновлено.

XElement.ReplaceAll()

Метод ReplaceAll зручний для заміни цілого поддерева XML, що починається з елемента. Цьому методу можна передавати просте значення, таке як новий рядок чи числового типу. Оскільки доступна перевантажена версія методу, що приймає безліч об'єктів через ключове слово params, можна замінити ціле поддерево. Метод ReplaceAll також замінює атрибути:

Зверніть увагу, що при заміні вмісту за допомогою методу ReplaceAll вказано атрибут. Як і можна було очікувати, вміст замінено:

даних

Зверніть увагу, що атрибут типу Employeeзник. Цікаво, що атрибути є дочірніми вузлами елемента. Тим не менш, метод ReplaceAll замінює їх також.

Метод XElement.SetElementValue()

Не дозволяйте цьому методу з простим ім'ям ввести вас в оману. Він має здатність додавати, змінювати та видаляти елементи. Більше того, він виконує ці операції на дочірніх елементах елемента, на якому викликається. Інакше кажучи, метод SetElementValue викликається на батьківському елементі, щоб вплинути його вміст, тобто. на дочірніх елементів.

При виклику методу SetElementValue передається ім'я дочірнього елемента, значення якого має бути встановлене. Якщо дочірній елемент знайдено на ім'я, його значення оновлюється, якщо тільки передане значення не дорівнює null. Коли передається null, знайдений дочірній елемент видаляється. Якщо елемент із зазначеним ім'ям не виявлено, він буде доданий з переданим значенням. Чудовий метод!

Також метод SetElementValue зачіпає лише перший дочірній елемент із зазначеним ім'ям, яке він знаходить. Всі наступні елементи з тим же ім'ям не торкаються — зміна значення або видалення елемента через передачу значення null. Нижче демонструються всі застосування цього методу: оновлення, додавання та видалення:

зміна

Виходячи з того, що виклик методу SetElementValue зі значенням null призводить до видалення вузла, не слід думати, що встановлення вручну значення елемента в null - це те саме, що і видалення його засобами LINQ to XML. Це просто поведінка методу SetElementValue. Якщо ви спробуєте встановити значення елемента в null, за допомогою властивості value, буде згенеровано виняток.