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

Вообще я в последнее время стараюсь избегать использовать в разработке какие-либо сторонние компоненты и библиотеки, исключением было использование Synapse для работы с HTTP/HTTPS — очень уж я привык к использованию этой простой библиотеки, опять же, не дай бог, придется под Lazarus проект переносить — меньше проблем будет.
А тут вдруг пару раз мне посоветовали использовать при работе с XML разработку SimDesignNativeXML. В качестве аргументов были «малый размер exe-шника», «удобство», «простота использования» и т.д. Решил проверить, попробовал…понравилось :).
NativeXML — это Open Sourse проект, доступен всем и каждому абсолютно бесплатно. Последняя версия 3.06. Конечно, после использования только стандартных средств для обработки XML библиотека NativeXML выглядит несколько необычно, но разобраться с ней достаточно просто. Чем мы сейчас и займемся.

Изучение начнем с установки NativeXML.

Установка и настройка NativeXML

Скачиваем zip-архив с установочным файлом, распаковываем и устанавливаем библиотеку. Если установка проведена по умолчанию, то все файлы NativeXML будут располагаться в директории:

C:/Program Files/NativeXML/

Где Вы можете найти:

  1. Документацию по библиотеке (на английском) в папке Documentation
  2. Пять примеров работы с NativeXML
  3. Папку Source с исходниками

В исходниках Вы обнаружите всего три файла: NativeXML.pas, NativeXmlObjectStorage.pas и NativeXmlAppend.pas.
Первый файл — NativeXML.pas — это исходник, содержащий все необходимые функции и обеты для работы с XML.
NativeXmlObjectStorage.pas…не довелось ещё его использовать «на полную катушку», но судя по описанию — это небольшая надстройка для хранения объектов в виде XML-файлов.
NativeXmlAppend.pas используется в случаях, когда необходимо добавить какой-либо фрагмент XML в конец существующего файла.
Для нас важно сегодня научиться пользоваться основой — NativeXML.pas.
Теперь, после установки библиотеки на свой компьютер Вы можете пойти двумя путями:

  1. Просто положить в папку с проектом файл NativeXML.pas, подключить его в uses и использовать его методы.
  2. Указать в настройках Delphi 2010 путь к папке Source.

В целом результат будет один и тот же — вы сможете использовать NativeXML в своем приложении.

Надеюсь, что с установкой и настройкой проблем у Вас не возникнет. Теперь приступим к изучению библиотеки. Во-первых, научимся читать данные из XML-файла.

Чтение данных из XML-файла

В качестве источника, предлагаю использовать любой RSS-канал, например мой. Почему именно RSS?
Во-первых, для получения данных с RSS-канала, нам не потребуется делать лишних «телодвижений», канал доступен, исходник XML получить легко, используя тот же Indy или Synapse.
Во-вторых, в RSS-канале мы можем встретить практически все «тонкие места», которые вызывают трудности при парсинге, например секции CDATA, пространства имен и т.д.
Создадим простенькое приложение, как показано на рисунке:

По указанному URL будем скачивать исходник XML и выводить его в Memo. Затем прочитаем все элементы RSS-канала и:
1. Выведем общее количество постов блога, находящихся в RSS-потоке
2. Заполним ComboBox заголовками постов
3. Прочитаем ключевые слова (теги, категории) постов — они содержатся в CDATA.
4. Выведем дату публикации сообщений.
Подключаем в uses модули:

uses ... NativeXML, httpsend {httpsend - для Synapse};

Теперь получаем исходник XML:

procedure TForm3.Button1Click(Sender: TObject);
begin
  with THTTPSend.Create do
    begin
      if HTTPMethod('GET',Edit1.Text) then
        begin
          Memo1.Clear;
          Memo1.Lines.LoadFromStream(Document, TEncoding.UTF8);
        end;
    end;
end;

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

  XMLDoc: TNativeXml; //объект XML-документа
  NodeList: TXmlNodeList;//список узлов

Первая процедура:

procedure TForm3.ParseXML(const XML: TStream);
var i:integer;
begin
  XMLDoc:=TNativeXml.Create;//создаем экземпляр класса
  XMLDoc.LoadFromStream(XML);//загружаем данные из потока
  if XMLDoc.IsEmpty then
    raise Exception.Create('Пустой XML! Работа прервана!');
  NodeList:=TXmlNodeList.Create;
  XMLDoc.Root.FindNodes('item',NodeList);//получаем список узлов Item
  label4.Caption:=IntToStr(NodeList.Count);
  {парсим каждый узел Item}
  ComboBox1.Items.Clear;
  for I := 0 to NodeList.Count - 1 do
     ComboBox1.Items.Add(NodeList.Items[i].NodeByName('title').ValueAsString);
end;

Теперь, при выборе в ComboBox какого-либо элемента мы должны вывести в Edit’ы ключевые слова и дату публикации. Так как ключевики содержаться в элементах CDATA, то следует заметить следующее:

тэги CDATA рассматриваются в NativeXML как дочерние узлы элемента, имеющие тип xeCData.

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

procedure TForm3.ComboBox1Change(Sender: TObject);
var Category: TXMLNodeList;
    i:integer;
begin
Edit2.Text:='';
Edit3.Text:='';
  with NodeList.Items[ComboBox1.ItemIndex] do
    begin
      Category:=TXmlNodeList.Create;
      Edit3.Text:=NodeByName('pubDate').ValueAsString;
      NodesByName('category',Category);
      for I := 0 to Category.Count - 1 do
         Edit2.Text:=Edit2.Text+Category.Items[i].NodeByElementType(xeCData).ValueAsString+', ';
    end;
end;

Теперь немного поразбираемся с тем, что мы собственно тут наделали. Итак, вначале мы создаем экземпляр класса TNativeXML и загружаем в него данные из потока. Если проводить аналогию со стандартными средствами для работы с XML в Delphi, то TNativeXML — это то же самое, что и TXMLDocument.
Далее мы выводили в ComboBox названия постов и делали это в цикле:

for I := 0 to NodeList.Count - 1 do
     ComboBox1.Items.Add(NodeList.Items[i].NodeByName('title').ValueAsString);

Здесь мы выбираем отдельный элемент TXMLNode из списка узлов TXmlNodeList. При этом узел мы находим по имени (title). Затем мы читаем содержимое узла как простую строку UTF8String.
Одной из замечательных возможностей NativeXML является то, что мы можем читать содержимое узла и тут же автоматически его приводить к необходимому типу данных. Например так:

NodeList.Items[i].NodeByName('AnyNode').ValueAsInteger

я прочитал содержимое узла и привел его к значение к типу Integer. Аналогичным образом можно работать даже с такими типами как Boolean, DateTime и т.д. — NativeXML позволяет нам сильно не задумываться о том как преобразовать данные узла.
При работе с отдельным элементом RSS-потока мы дополнительно использовали ещё одну возможность NativeXML — выбор узла по его типу:

Category.Items[i].NodeByElementType(xeCData).ValueAsString

Здесь мы выбрали узел из списка, у этого узла выделили узел с типом xeCData и прочитали содержимое этого узла.
Всего в NativeXML используется 14 различных типов узлов, от обычных xeNormal, до таких специфичных как xeEntity (< !ENTITY >). Вы можете использовать эти типы данных для поиска узлов или записи данных в файл.
Похожим образом организована работа NativeXML и с атрибутами узла. Для примера, прочитаем атрибут вот этого узла из RSS:

< guid isPermaLink="false">http://webdelphi.ru/?p=3349< / guid >

Чтение атрибута, имеющего тип boolean:

NodeByName('guid').ReadAttributeBool('isPermaLink')

Также помимо приведения значений атрибутов к типам данных Boolean, Integer, double и т.д. вы можете использовать также приведение к таким типам как TPen или TRect.
Теперь выполним обратныю операцию — запись данных в XML-файл.

Запись данных в XML-файл

Попробуем записать простенький XML-файл, содержащий несколько узлов, например так:

procedure TForm3.Button2Click(Sender: TObject);
var XMLDoc: TNativeXml;
    Node: TXmlNode;
begin
  XMLDoc:=TNativeXml.Create;//создали документ
  XMLDoc.CreateName('RootNode');//создали корневой узел
  //создаем дочерний узел
  Node:=TXmlNode.Create(nil);
  Node.Name:='FirstNode';
  Node.ValueAsString:='Значение узла';
  Node.AttributeAdd('attr_integer',12);//добавляем атрибут integer
  Node.WriteAttributeDateTime('attr_date',Now);//другой способ. записываем дату
  XMLDoc.Root.NodeAdd(Node);
  {второй узел: другой вариант записи}
  XMLDoc.Root.NodeNew('SecondNode').ValueAsBool:=false;
  XMLDoc.SaveToFile('MyXML.xml');
end;

В итоге получим XML-документ следующего содержания:

Теперь попробуем немного усложнить заачу и записать узел, содержащий секцию CDATA. Сделать это можно, например так:

var WithCdata, NodeCDATA: TXmlNode;
...
  WithCdata:=TXmlNode.Create(nil);
  NodeCDATA:=TXmlNode.CreateType(XMLDoc,xeCData);
  NodeCDATA.ValueAsString:='Это строка в CDATA';
  WithCdata.Name:='WithCdata';
  WithCdata.NodeAdd(NodeCDATA);
  XMLDoc.Root.NodeAdd(WithCdata);
...

В итоге наш документ примет следующий вид:

Ну и, наконец пара моментов связанных с изменением кодировки документа, версии xml и т.д. Такие изменения следует проводить после добавления корневого узла. Например так:

XMLDoc:=TNativeXml.Create;//создали документ
  XMLDoc.CreateName('RootNode');//создали корневой узел
  //задаем параметры документа
  XMLDoc.WriteOnDefault:=false;
  XMLDoc.CommentString:='Комментарий к файлу';
  XMLDoc.EncodingString:='UTF-8';
  XMLDoc.VersionString:='1.0';

Я задал кодировку документа, версию и дополнительно записал комментарий к файлу. Обратите внимание, что перед этим я заменил свойство:

XMLDoc.WriteOnDefault:=false;

То есть отключил запись документа по умолчанию.
Вот пожалуй и все по поводу первого знакомства с NativeXML в Delphi. Надеюсь, что статья поможет вам начать работу с этой библиотекой и разобраться более детально с её работой.

Скачать исходник: Исходники —> XML и JSON в Delphi
5 1 голос
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
19 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
atruhin
atruhin
05/05/2010 22:26

Все эти самописные компоненты хороши пока не сравниваем возможности и скорость работы. И вот тут получается что стандартный MSXML, есть в любой windows ОС, быстрее (по моим данным в разы) и имеет несравнимо больше возможностей.

vbif
vbif
06/02/2013 15:09
Ответить на  atruhin

А как он относится к большим файлам? К примеру, файл на 34М сложной структуры он нормально распарсит?

featZima
featZima
10/05/2010 10:40

А речь идёт как раз о переносимости на другие платформы) Лично мне нравится кросплатформенный libxml, не знаю есть ли реализация на Delphi, но в любом случае можно реализовать варпер…

JokerBaD
JokerBaD
18/02/2011 15:54

Ребята помогите пожалуйста!Как прочитать и такую кострукцию!!! я имею ввиду simpleChoice верхний элемент считываю «Демокрит» а другие не получаются подскажите
<itemBody>
<p>Воспитателем Александра Македонского был </p>
<choiceInteraction shuffle=»true» maxChoices=»1″>
<simpleChoice identifier=»3″>Демокрит</simpleChoice>
<simpleChoice identifier=»2″>Гераклит</simpleChoice>
<simpleChoice identifier=»1″>Аристотель</simpleChoice>
<simpleChoice identifier=»0″>Платон</simpleChoice>
</choiceInteraction>
</itemBody>

JokerBaD
JokerBaD
19/02/2011 10:05

вот что получилось  NodesByName(‘choiceInteraction’,choiceInteraction);
if FirstList.Items[ComboBox2.ItemIndex].NodeByName(‘choiceInteraction’) <> nil then
begin
memo1.Clear;
for j := 0 to choiceInteraction.Items[0].NodeCount — 1 do
memo1.Lines.Add(VarToStr(Utf8ToAnsi(choiceInteraction.Items[0].Nodes[j].ValueAsString)));

memo2.Clear;
for l := 0 to choiceInteraction.Items[0].NodeCount — 1 do
memo2.Lines.Add(VarToStr(Utf8ToAnsi(choiceInteraction.Items[0].Nodes[l].ReadAttributeString(‘identifier’))));
end;

JokerBaD
JokerBaD
19/02/2011 10:13

Спс Vlad!Разобрался!все равно если 5 и больше simpleChoice то выводит в мемо 4???Как тут правильно цикл реализовать подскажите пожалуйсто!

JokerBaD
JokerBaD
19/02/2011 11:47

неееее все работает))))Спс

BuTeK
BuTeK
07/06/2011 17:06

Очень полезный компонент для тех кто собирается сэкономить и купить Delphi XE Starter (я например), так как нету в нет TXMLDocuments.

Мирослав
Мирослав
04/08/2011 18:34

А кто нибудь пробовал заточить NativeXML под Lazarus. Сходу не получилось.

BuTeK
BuTeK
21/09/2011 01:00

Интересно, а под Delphi XE2 запустится спокойно?

bas
bas
08/11/2011 17:45

Скачал версию 402 и решил попробовать —   Node:=TXmlNode.Create(nil); — ошибка.
Нету у TXmlNode такого. 

ter
ter
09/12/2011 19:05

потому что CreateParent там вроде конструктор. у которого два параметра — владелец, и родительский узел.
 
 
зы: попробовал тут пару раз использовать, при записи очень шустрый, а при чтении данных че то вообще провал. либо хз. надо разбираться в чем проблема.

Vanyk
Vanyk
15/12/2011 20:38

бомба для работы с Cdata

Анонимно
07/07/2016 19:42

херня полная этот nativexml — не работает в xe6