Как стать автором
Обновить

Кто сильнее: XDocument или XmlDocument, или как я приручал табличные редакторы

Уровень сложностиСредний
Время на прочтение16 мин
Количество просмотров2K

Привет! Я Кирилл Пронин, разработчик PIX RPA из PIX Robotics. В этой статье расскажу о том, как мы учили наш продукт работать с импортозамещенными табличными редакторами в Linux-подобных операционных системах, кто сильнее - XDocument или XmlDocument, и какие лайфхаки я унес с собой.

Как часто вы задумываетесь о выборе правильного типа данных в своей будущей разработке? Следите ли вы за последними изменениями в работе с XML-документами?

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

Как в короткие сроки разработать код, который умеет работать со всеми файлами Linux-аналогов Excel? И хотя каждый табличный редактор — это простейший XML, как разработать одну структуру, которая умеет работать со всеми? Правда ли, что XmlDocument — это старый добрый тип, который всегда актуален и до сих пор силен? Или появились новые типы, о которых просто не говорят так много и повсеместно?

Рассмотрим лучшие и худшие стороны XDocument и XmlDocument на практических примерах. Узнаем о лайфхаках использования и обратимся к бенчмаркам.

В PIX мы разрабатываем несколько продуктов, я работаю непосредственно над разработкой PIX Studio - визуальной средой разработки программного робота (RPA). RPA, скажем, больше заточено на визуальное программирование: у нас есть активности, они же действия, которые программный робот может выполнять, и как раз эти действия мы разрабатываем, публикуем, развиваем и т.д. и т.п. И взаимодействие с текстовыми и табличными редакторами – один из самых частых сценариев.

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

PIX Studio уже работал с таблицами Microsoft Excel, а теперь надо было сделать то же самое, но на другой ОС. Аналог Excel на Linux-подобных операционных системах.

Да, Linux-подобных операционных систем много, и сама суть всей этой прикольной истории в том, что каждый Linux-подобная ОС реализует свой аналог табличного редактора.

Грубо говоря, ситуация такая:

Получается, что нам всего-навсего нужно разработать универсальное решение, которое будет работать в принципе везде, и запускаться везде, и данные будут парситься везде.

Ну что ж, давайте теперь перейдем на путь решения.

Путь первый: API

Первый путь решения, который приходит на ум, это научиться обрабатывать самые распространенные офисные пакеты, создавать провайдеры или движки, брать всю логику, апишечки, потеть над каждым офисным пакетом. То есть сегодня реализовали LibreOffice, потом реализовали Polaris, потом MoйOffice, потом RedOffice, и так далее.

Создаем сейчас шесть штук, потом еще восемь, и впоследствии мы сделаем такой мини-заводик по производству функционала на основе апишечек разных офисных пакетов.

Но есть там огромное НО: каждая апишечка весит по 100 мегабайт плюсом, а ты будешь использовать 5% от нее. Твой проект становится огромным.

И тут подлетает другая проблема:

Некоторые компании делают одну апишечку для всего офисного пакета, просто дергай, используй ее, пожалуйста, результат будет. А другие же говорят, нет, ну вот на каждый продукт можно докачать 100 мегабайт, и вот, пожалуйста, вам будет поддержка.

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

Путь второй: ODF + общий предок

Все офисные пакеты Linux изначально основаны на ODF - это Open Document Format, а значит они между собой немножечко похожи. Надо найти общего предка и общаться универсально по стандартам этого общего предка, чтобы все его понимали. Значит, нужно понять, откуда все пошло, поэтому я прогуглил (универсальный шаг номер 0), и увидел такую вещь как иерархии офисных пакетов, и выглядит она вот так:

Классная ветка метро, мне прям все нравится.

Что же делать? Надо найти что-то найти общее. Соответственно, если долго смотреть, можно понять, что все пришло из Star Office, но тут есть маленькая проблемка.

Star Office — это история прям максимально допотопная, с которой нам будет очень тяжело работать. Чтобы наши современные офисные пакеты начали его понимать, нам придется реализовывать инструмент конвертации из типа стар офиса в какой-то чуть-чуть поновее, и чтобы этот чуть-чуть поновей, уже сам новый наш офисный пакет распознал и понял. 

Но если приглядеться в историю создания и развития, можно понять, что основой всех ветвей является Apache OpenOffice (поддерживается до сих пор, а значит, ее можно назвать современной технологией), плюс к этому мы получаем преемственность решений, так как другие движки могут нас с вами понять, ведь мы общаемся на языке общего предка (как будто версии приложения на единичку ниже), даже Libre Office (отличающийся особенной сложностью) пристроит свое решение под себя. Отлично. Значит, примерно поняли, куда мы двигаемся и что для чего будем разрабатывать.

Подводим первые итоги

Разрабатываем мы для Apache OpenOffice.

Для него нет никакого API.

Отсюда мы автоматически понимаем, что делаем все ручками.

Теперь погрузимся немножко в теорию.

Что такое OpenOffice таблица?

Open Office Calc это тот же самый Excel, который мы видим каждый день, просто немножечко визуально старее. Но технология, терминология, функционал - один в один.

По своей сути это *.ods файл, архив, внутри которого располагаются все наши настройки и данные. А сами данные, хранятся в виде XML файла Content.xml.

Если разархивировать такой файл, увидим такую картину.

Поздравляю, вы нашли данные. Ура!

Что мы делаем?

Мы подрубаем открытие архивного файла, считываем только Content.xml, и в результате получаем XML-код. Ура!

Все офисное ПО базируется на XML

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

Да, если мы с вами каждый день работаем с XML-кой, мы видим чаще всего использование просто элементов и текстового содержимого. Например, так

<book id="bk101">
	<author>Gambardella, Matthew</author>
	<title>XML Developer's Guide</title>
	<genre>Computer</genre>
	<price>44.95</price>
	<publish_date>2000-10-01</publish_date>
	<description>
		An in-depth look at creating applications
		with XML.
	</description>
</book>

В офисном документе эта история выглядит сложнее, все возможности XML в одном месте.

То есть у нас есть и элементы, и атрибуты, и текстовое содержимое, и неймспейсы.

А вот как это выглядит под капотом.

<office:spreadsheet>
	<table:table table:name="Лист1" table:style-name="ta1" table:print="false">
		<table:table-column table:style-name="co1" table:default-cell-style-name="ce2"/>
		<table:table-column table:style-name="co2" table:default-cell-style-name="ce4"/>
		<table:table-column table:style-name="co3" table:default-cell-style-name="ce6"/>
		<table:table-row table:style-name="ro1">
			<table:table-cell table:style-name="Default" table:number-columns-repeated="3"/>
		</table:table-row>
		<table:table-row table:style-name="ro2">
			<table:table-cell table:style-name="ce1" office:value-type="string">
				<text:p>№</text:p>
			</table:table-cell>
			<table:table-cell table:style-name="ce3" office:value-type="string">
				<text:p>Работы/материалы</text:p>
			</table:table-cell>
			<table:table-cell table:style-name="ce3" office:value-type="string">
				<text:p>Стоимость</text:p>
			</table:table-cell>
		</table:table-row>
		...

Но если присмотреться, понимаем, что все это одна структура: сверху идет лист, внутри листа располагаются строчки, внутри строчки располагаются ячейки, внутри ячейки типы и внутри типы значения.

В принципе, мы рекурсивно можем считать и получить значение из ячейки.

Логика примерно ясна, просто это выглядит страшно, а на самом деле ничего страшного нет.

Как обработать XML-формат?

С# предоставляет множество классов, и самый популярный находится в системе XML, он называется XmlDocument.

Почему он популярен? Давайте прогуглим (снова!)!

Найдем миллион статей, чаще всего мы будем видеть XmlReader, XmlDocument.

XmlDocument вообще универсальная история, которая будет с нами всегда, и больше всего примеров Nuget-пакетов реализована на XmlDocument, больше всего примеров в статьях реализована на XmlDocument.

И создается такое впечатление, что XmlDocument настолько популярна история, что на нее можно найти ответ на каждом форуме, а значит она, наверное, и сильнее.

XDocument же как будто не такой популярный и имеет поменьше информации в интернете.

Окей, давайте попробуем в XmlDocument.

Время написать код для будущего обработчика табличек

using ZipArchive zArchive = new(stream);
ZipArchiveEntry? entry = zArchive.GetEntry("content.xml");

// Проверка на правильное считывание файла
if (entry is null)
{
    throw new InvalidOperationException();
}

var streamXML = entry.Open();
XmlDocument doc = new XmlDocument();
doc.Load(streamXML);

XmlNamespaceManager nmsManager = new XmlNamespaceManager(doc.NameTable);

foreach (KeyValuePair<string,string> eachNamespace in _namespaces)
    nmsManager.AddNamespace(eachNamespace.Key, eachNamespace.Value);

Берем путь к файлу, файловый поток, запихиваем zip-архив в стрим.

Зачем? Нам надо разархивировать, и взять только entry point под названием content.xml.

Почему я беру только его?

Главная задача стояла получить значение ячеек, уметь их модифицировать, сохранять.

Когда мы работаем с данными, которые лежат в офисном документе, и нам важно обрабатывать только данные, они лежат непосредственно только в content.xml.

Далее, нам необходимо этот content.xml запихнуть в XmlDocument.

Соответственно, мы создаем класс XmlDocument, передаем через .load информацию, и, поздравляю, XmlDocument у нас заполнен тем, что у нас было в офисном документе.

Подключаем NamespaceManager, заполнив его информацией о названии таблицы, и через цикл мы подключаем каждый namespace к нашему NamespaceManager.

И сразу появляется вопрос, а что это вообще такое namespace для офисного документа?

private static Dictionary<string,string> _namespaces = new Dictionary<string, string>
{
        {"table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0"},
        {"office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0"},
        {"style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0"},
        {"text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0"},
        {"draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"},
        {"fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"},
        {"dc", "http://purl.org/dc/elements/1.1/"},
        {"meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0"},
        {"number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"},
        {"presentation", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"},
        {"svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"},
        {"chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0"},
        {"dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"},
        {"math", "http://www.w3.org/1998/Math/MathML"},
        {"form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0"},
        {"script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0"},
        {"ooo", "http://openoffice.org/2004/office"},
        {"ooow", "http://openoffice.org/2004/writer"},
        {"oooc", "http://openoffice.org/2004/calc"},
        {"dom", "http://www.w3.org/2001/xml-events"},
        {"xforms", "http://www.w3.org/2002/xforms"},
        {"xsd", "http://www.w3.org/2001/XMLSchema"},
        {"xsi", "http://www.w3.org/2001/XMLSchema-instance"},
        {"rpt", "http://openoffice.org/2005/report"},
        {"of", "urn:oasis:names:tc:opendocument:xmlns:of:1.2"},
        {"rdfa", "http://docs.oasis-open.org/opendocument/meta/rdfa#"},
        {"config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0"}
};

Namespace - это все структуры, с которыми мы будем работать, грубо говоря, зависимости.

Соответственно, чем больше и богаче данные, которые лежат у нас в таблице, тем больше зависимости на Namespace у них будут.

Изначально, конечно, самые простые зависимости, то есть первые четыре: table, office, style и text.

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

И как только мы начинаем искать и разбираться с этой историей, мы же можем туда засунуть график, формочку, конфиг и так далее. Наш табличный документ многогранен и может по-разному использоваться.

И заранее говорю, я подключаю все.

На самом деле каждый разработчик может подключать неймспейсы, если вы заранее понимаете, что в обработке документов у вас ничего не будет, кроме данных и обычных стилей.

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

Первый метод, который мы с вами пишем, это GetSheet

private DataTable GetSheet(XmlNode tableNode, XmlNamespaceManager nmsManager)
{
    DataTable sheet = new DataTable(tableNode.Attributes["table:name"].Value);

    XmlNodeList rowNodes = tableNode.SelectNodes("table:table-row", nmsManager);

    int rowIndex = 0;
    foreach (XmlNode rowNode in rowNodes)
        this.GetRow(rowNode, sheet, nmsManager, ref rowIndex);

    return sheet;
}

Соответственно, мы просто-напросто в XML-ноду запихиваем XML-документ, подключаем к нему еще дополнительно NamespaceManager, который мы заранее проинициализировали с помощью добавления неймспейсов.

Cначала создаем DataTable, говорю ему, что у меня нода, у нее есть атрибут table:name, мне нужно ее value.

Далее мы вызываем SelectNode и выбираем table-row.

В цикле foreach вызываем и делаем метод GetRow

private void GetRow(XmlNode rowNode, DataTable sheet, XmlNamespaceManager nmsManager, ref int rowIndex)
{
    XmlAttribute rowsRepeated = rowNode.Attributes["table:number-rows-repeated"];
    if (rowsRepeated == null || int.Parse(rowsRepeated.Value, CultureInfo.InvariantCulture) == 1)
    {
        while (sheet.Rows.Count < rowIndex)
            sheet.Rows.Add(sheet.NewRow());

        DataRow row = sheet.NewRow();

        XmlNodeList cellNodes = rowNode.SelectNodes("table:table-cell", nmsManager);
	int cellIndex = 0;
	foreach (XmlNode cellNode in cellNodes)
	{
    		var value = GetCell(cellNode, row, ref cellIndex);
		...

В GetRow пропихиваем весь лист, чтобы он понимал, где мы находимся и заполнял данные.

NamespaceManager, который мы там тоже будем использовать.

И row.index, чтобы мы не запутались.

Происходит все почти то же самое.

Кроме одного условия, мы запрашиваем список атрибутов у нашей row.node.

И обязательно говорим ему, что нам нужно number row.repeated.

То есть сначала нам надо понять, сколько строчек повторяются.

Уникальность этого решения в том, что офисные пакеты, почти все, которые основаны на Open Document Format, сжимают повторяющиеся значения. То есть, если у нас информация, например, находится где-нибудь в ячейке C3, все пустоты до С3, он будет объединять в узлы. Он не будет говорить вам, что есть ячейка A1, A2, A3, ... - они пустые. Нет. Он объединяет одинаковые значения. В документе будет один узел с названием numberRowRepeated, в котором будет написано, сколько строчек повторяется.

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

Мы в данном случае пишем как раз метод SelectNodes и в нем говорим, что нам нужно.

Да, NamespaceManager мы продолжаем таскать с собой.

GetCell, аналогично предыдущему.

private string GetCell(XmlNode cellNode, DataRow row, ref int cellIndex)
{
    XmlAttribute cellRepeated = cellNode.Attributes["table:number-columns-repeated"];
    string cellValue = this.ReadCellValue(cellNode);
    return cellValue;
}

Мы просто-напросто берем ее атрибуты, чистим информацию по поводу того, сколько у нас колонок повторяется, потому что с ячейками такая же история, как со строками, и далее вызываем метод ReadCellValue по нужной нам ноде, и в нем берем атрибут office:value.

private string ReadCellValue(XmlNode cell)
{
    XmlAttribute cellVal = cell.Attributes["office:value"];

    if (cellVal == null)
        return cell.InnerText;
    else
        return cellVal.Value;
}

Мы добрались до значения!

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

Не нужно дополнительно внутри рассматривать логику, делать дополнительный движок на то, чтобы модифицировать информацию, например, узел удалить, узел вставить, и так далее. Внутри файла документа мы перезаписываем внутренность под названием content.xml.

А потом я вижу XDocument ...

Случайным образом, путем гугления и поиска какое-какой интересной информации, я заметил, что на самом деле существует XDocument.

 И попросил я нейроночку мне помочь: написать добавление узла в ячейку Open Office на основе XDocument? (да, мне пришлось самому доработать, но приятно же вовлечь еще кого-то).

string filePath = "путь_к_файлу.ods";

// Загрузка файла .ods в XDocument
XDocument document = XDocument.Load(filePath);

// Находим таблицу в файле
XElement table = document.Descendants().FirstOrDefault(e => e.Name.LocalName == "table");

// Создаем новую ячейку
XElement newCell = new XElement(XName.Get("table-cell", "urn:oasis:names:tc:opendocument:xmlns:table:1.0"));

// Устанавливаем значение ячейки
newCell.Add(new XElement(XName.Get("p", "urn:oasis:names:tc:opendocument:xmlns:text:1.0"), "Значение ячейки"));

// Добавляем новую ячейку в таблицу
table.Add(newCell);
        
// Сохраняем изменения обратно в файл .ods
document.Save(filePath);
Console.WriteLine("Ячейка успешно добавлена!");

Что получилось? У нас есть некий путь к файлу, который подгружается в XDocument, и потом начинается самое интересное. Новый для меня в .NET по работе с XDocument метод оказался Descendants(), который перечисляет все внутренние узлы. В нашем случае находим только табличные данные и вызываем add, то есть добавляем после него новый узел.

Сохраняем – и ячейка добавлена. Интересно! Давайте покопаемся.

Для начала создадим метод AppendChild, который реализует добавление какого-либо узла внутрь xml.

Как это выглядит с XmlDocument:

public void AppendChildNode_XmlDocument(XmlDocument doc)
{
    // Создание нового элемента
    XmlElement newElement = doc.CreateElement("book");

    // Добавление атрибута к элементу
    newElement.SetAttribute("category", "fiction");

    // Создание и добавление дочерних элементов
    XmlElement titleElement = doc.CreateElement("title");
    titleElement.InnerText = "The Great Gatsby";
    newElement.AppendChild(titleElement);

    // Добавление нового элемента в корневой элемент документа
    doc.DocumentElement.AppendChild(newElement);
}

Как это выглядит с XDocument:

public void AppendChildNode_XDocument(XDocument doc)
{
    // Создание нового элемента
    XElement newElement = new XElement("book",
        new XAttribute("category", "fiction"),
        new XElement("title", "The Great Gatsby"),
        new XElement("author", "F. Scott Fitzgerald")
    );

    // Добавление нового элемента в корневой элемент документа
    doc.Root.Add(newElement);
}

Да это магия в чистом виде! Стало удобно не только понимать и читать что происходит в коде, но и написание этого метода гораздо проще!

Что же такое XDocument?

Это класс в пространстве system.xml.linq. Представляет он xml-документ в виде объектов памяти. В отличие от XmlDocument из пространства имен system.xml, XDocument предоставляет более современные и удобные API для работы с xml в языке С#.

Eсли XmlDocument употреблялся еще с первых версий и языков, то XDocument добавился к нам с .Net Framework 3.5.

Но есть небольшая проблема – когда XDocument только зарелизился, многие разработчики начали его использовать и увидели в нем больше недостатков, чем плюсов по сравнению с XmlDocument. С тех времен мало кто использовал в разработке XDoc (XDocument), из-за этого этот тип данных стал серой лошадкой. И начиная с .NET6/.NET7 он приобрел огромное количество новых методов и расширений, что позволило его еще гибче использовать с LINQ. Начиная с .NET7 – XDoc стал мощнее и интереснее!

Некоторые из достоинств XDocument по сравнению с XmlDocument

1) Более простой и интуитивно понятный синтаксис

2) Удобное добавление и удаление элементов

3) Поддержка пространств имен

4) Использование нескольких файлов и фрагментов

5) Поддержка LINQ-запросов

Многие скажут: наверное, в XDocument проблема с запоминанием пустоты?

Нет! XmlDocument & XDocument помнят абсолютно всю структуру XML-документа. Но…

XmlNode (XmlDocument) работает, так как по-другому не умеет.

XNode (XDocument) дает возможность разработчику выбрать нужный вариант записи.

XDocument doc = XDocument.Load(ms);

doc.Save("SomeFile.xml", SaveOptions.DisableFormatting);

Важно уметь применять это в нужный момент!

Немного про память

XmlDocument загружает всю структуру XML-документа в память, что может потребовать большое количество памяти, особенно при работе с большими файлами XML.

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

Но! Если в решении присутствует использование всего XDocument сразу, а не его блочное деление и вызов определенных модулей, то никакой ленивой загрузки не будет. И преимущество окажется недостатком.

Описываем обработчик табличек на XDocument

Давайте попробуем написать то же самое, тот же обработчик табличек, только на другом типе данных.

XDocument doc = XDocument.Load(streamXML);

var reader = doc.CreateReader();
XmlNamespaceManager nmsManager = new XmlNamespaceManager(reader.NameTable);

foreach (KeyValuePair<string, string> eachNamespace in _namespaces)
    nmsManager.AddNamespace(eachNamespace.Key, eachNamespace.Value);

var nodes = doc.XPathSelectElements("/office:document-content/office:body/office:spreadsheet/table:table", nmsManager);
// Больше nmsManager не нужен

foreach (XElement node in nodes)
    GetSheet(node);

Берем вот этот вот стрим.xml, запихиваем его в метод.load. Создаем ему reader. Говорим ему:  давай на NamespaceManager подрубим. (Да, здесь он нам потребуется только для взятия XPath).

Далее с помощью XPathSeleceElements говорим, что нам необходимо получить только table с указанными родителями: как итог мы получим перечисление всех листов.

И то, что мы получили, передаем в новый метод GetSheet.

public static List<string> GetSheet(XElement tableNode)
{
    return tableNode.Elements()
                    .Where(x => x.Name.LocalName == "table-row")
                    .SelectMany(GetRow)
                    .ToList();
}

На вход GetSheet получили XElenent листа. Нам же нужно запросить все его элементы в виде перечисления (Elements()), выбрать только имена с table-row и передать их в метод GetRow.

public static List<string> GetRow(XElement rowNode)
{
    return rowNode.Elements()
                  .Where(x => x.Name.LocalName == "table-cell")
                  .Select(GetCell)
                  .ToList();
}

Внутри GetRow – аналогично, запрашиваем все внутренние элементы, забираем только table-cell, и передаем в GetCell метод

public static string GetCell(XElement cellNode)
{
    string? textValue = cellNode.Elements().FirstOrDefault(x => x.Name.LocalName == "p")?.Value;
    return textValue;
}

Внутри GetCell запрашиваем все элементы внутри ячейки и берем только «p», что означает параграф текста. Запрашиваем его значение и возвращаем.

Поздравляю! Табличный обработчик только для string значений готов.

Какие лайфхаки я могу посоветовать с XDocument?

Какие методы самые-самые для XDocument?

AddAfterSelf(Object)/AddBeforeSelf(Object) - Добавляет содержимое после/до данного узла.

Ancestors() - Возвращает коллекцию элементов-предков узла.

Descendants() - Возвращает коллекцию подчиненных узлов для данного документа или элемента.

Elements() - Возвращает коллекцию дочерних элементов.

IsAfter(XNode)/IsBefore(XNode) - Определяет, предшествует/следует ли текущий узел.

Для XElement:

Attributes() - Возвращает коллекцию атрибутов этого элемента.

Ну что же, мы выяснили, что с XDocument написать код проще и понятнее его прочитать, а он быстрее? Приведем несколько тестов.

Бенчмарк 1 - Load-Append-Remove на простом xml

Допустим, у меня есть библиотека книжек, и там указано около 10 книг по такой структуре

<book id="bk101">
	<author>Gambardella, Matthew</author>
	<title>XML Developer's Guide</title>
	<genre>Computer</genre>
	<price>44.95</price>
	<publish_date>2000-10-01</publish_date>
	<description>
		An in-depth look at creating applications
		with XML.
	</description>
</book>

Проведем тест на основе Load-Append-Remove для XMLDoc и XDoc.

Бенчмарк 2 - Взаимодействие с OpenOffice

Допустим, у меня есть заполненный табличный файл *.ods.

Проведем тест на основе Load-ReadData-Append-Remove для XMLDoc и XDoc.

Бенчмарк 3 - Взаимодействие с КЛАДР

Сделал выгрузку из ГАР (КЛАДР) и взял дельту изменений по одной улице.

Проведем тест на основе Load-Append-Remove для XMLDoc и XDoc.

Пора начинать подводить итоги

Всё в ваших … 

Как мы достигли быстрого выполнения обработки xml? – Попробовали XDocument и он помог в нашем случае.

Как так вышло, что решение работает на OpenOffice, Libre, МойОфис, РедОфис ..... ? – Общаемся на языке общего предка, а при открытии документа новые пакеты все под себя подстроят сами.

А как понять, можно ли внедрять XDocument? – Ориентироваться на опорные точки. Вот они:

1)     Версия .NET

2)     Размер *.xml файлов для обработки

3)     Возможность изменять легаси

Верю, у всех все получится, и иногда переизобретать велосипед – полезно.

А теперь, расскажите вы, уважаемые читатели. Как вы столкнулись с XMLDocument? Какие впечатления он оставил и пробовали ли XDocument? Или же вы суперспециалист, который может добавить то, что я не учел при написании статьи?

Буду рад любой оценке и любым комментариям, давайте покажем, что мир XML все еще хранит тайны и предпосылки к улучшениям.

Теги:
Хабы:
Всего голосов 12: ↑12 и ↓0+12
Комментарии27

Публикации

Информация

Сайт
www.pix.ru
Дата регистрации
Численность
101–200 человек