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


Изменение дерева 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-документов.