Поделиться через


Изменение дерева XML в памяти и функциональное построение (LINQ to XML)

Изменение дерева XML на месте — это традиционный подход к изменению формы XML-документа. Обычное приложение загружает документ в хранилище данных, например DOM или LINQ to XML; использует интерфейс программирования для вставки или удаления узлов или изменения их содержимого; затем сохраняет XML-файл или передает его по сети.

LINQ to XML позволяет использовать другой подход, который полезен во многих сценариях: функциональное построение. Функциональное построение рассматривает изменение данных как проблему преобразования, а не как подробную манипуляцию с хранилищем данных. Если вы можете эффективно преобразовать представление данных и преобразовать их из одной формы в другую, результат такой же, как если бы вы взяли одно хранилище данных и манипулировали им каким-то образом, чтобы получить другую форму. Ключом к подходу функционального построения является передача результатов запросов конструкторам XDocument и XElement.

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

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

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

<?xml version="1.0" encoding="utf-8" ?>
<Root Data1="123" Data2="456">
  <Child1>Content</Child1>
</Root>

Первый из следующих примеров использует традиционный подход изменения на месте, а второй использует функциональный подход к построению.

Пример: Преобразование атрибутов в элементы с помощью традиционного непосредственного подхода

Можно написать некоторый процедурный код для создания элементов из атрибутов, а затем удалить атрибуты следующим образом:

XElement root = XElement.Load("Data.xml");
foreach (XAttribute att in root.Attributes()) {
    root.Add(new XElement(att.Name, (string)att));
}
root.Attributes().Remove();
Console.WriteLine(root);
Dim root As XElement = XElement.Load("Data.xml")
For Each att As XAttribute In root.Attributes()
    root.Add(New XElement(att.Name, att.Value))
Next
root.Attributes().Remove()
Console.WriteLine(root)

В примере получается следующий вывод.

<Root>
  <Child1>Content</Child1>
  <Data1>123</Data1>
  <Data2>456</Data2>
</Root>

Пример. Преобразование атрибутов в элементы с помощью функционального подхода к построению

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

XElement root = XElement.Load("Data.xml");
XElement newTree = new XElement("Root",
    root.Element("Child1"),
    from att in root.Attributes()
    select new XElement(att.Name, (string)att)
);
Console.WriteLine(newTree);
Dim root As XElement = XElement.Load("Data.xml")
Dim newTree As XElement = _
    <Root>
        <%= root.<Child1> %>
        <%= From att In root.Attributes() _
            Select New XElement(att.Name, att.Value) %>
    </Root>
Console.WriteLine(newTree)

Этот пример выводит тот же XML-код, что и первый пример. Однако обратите внимание, что на самом деле можно увидеть итоговую структуру нового XML в функциональном подходе. Вы можете увидеть создание Root элемента, код, который извлекает Child1 элемент из исходного дерева, и код, который преобразует атрибуты из исходного дерева в элементы в новом дереве.

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

Обратите внимание, что в этом случае функциональный подход, вероятно, не будет работать так хорошо, как подход к манипуляции с деревьями. Основная проблема состоит в том, что функциональный подход создает больше кратковременных объектов. Однако компромисс является эффективным, если использовать функциональный подход позволяет повысить производительность программиста.

Это очень простой пример, но он служит для отображения разницы в философии между двумя подходами. Функциональный подход повышает производительность для преобразования больших XML-документов.