Сравнение изменения XML-дерева в памяти с функциональным построением (LINQ to XML)
Обновлен: November 2007
Изменение 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>
Изменение XML-дерева
Можно написать процедурный код, чтобы создать элементы из атрибутов, а затем удалить атрибуты. Вот как это делается:
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-документов.