Использование XML Document Object Model. Использование XML в среде Delphi

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

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

Предыстория . Сегодня понадобилось обработать данные об установленных программах на компьютерах пользователей (да, да, пиратов выявляем:)). Технический отдел предоставил мне такую информацию содраную с ничего не подозревающих пользователей по сети с использованием WMI . Программа, которой они пользовались выдает отчеты в формате XML. Соответственно - мне притащили гору XML файлов с довольно сложной структурой из которых мне необходимо было вытащить только название установленных программных продуктов.

Обработка . Просмотрев пару файлов вручную, понял что так и состариться не долго, и решил написать небольшой конвертер. Запустив Delphi - выбрал в репозитарии объект XML DataBinding и скормил ему один из файлов. Все настройки и параметры я оставил по умолчанию и в результате у меня сформировался модуль с большим количеством классов и интерфейсов для доступа к элементам этого XML файла. Я не стал долго разбираться со структурой классов, сразу же перешел к написанию конвертера.

В новом консольном приложении написал довольно простой код:


program XML2TXT;

uses
Forms,
Classes, SysUtils,
SoftwareXML in "SoftwareXML.pas";

procedure CovertXML2Text;
var
softbase: IXMLSTDSoftwareType;
i: integer;
sr: TSearchRec;
CurDir: string;
ExportFile: TStringList;
begin
CurDir:= IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
if FindFirst(CurDir+"*.xml", faAnyFile, sr) = 0 then
repeat
ExportFile:= TStringList.Create;
softbase:= LoadSTDSoftware(Pchar(CurDir+sr.Name));
for i:= 0 to softbase.InstalledSoftware.source.software.Count - 1 do
ExportFile.Add(softbase.InstalledSoftware.source.software[i].DisplayName);
ExportFile.Sort;
ExportFile.SaveToFile(CurDir + softbase.InstalledSoftware.Source.servername+".txt");
ExportFile.Free;
until FindNext(sr) 0;
end;

begin
Application.Initialize;
CovertXML2Text;
end.

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

Чувствую что данный код потребует пояснений. Например, зачем я в консольном приложении использовал модуль Forms и вызывал процедуру Application.Initialize;?

На самом деле все просто - это небольшой хак, позволяющий использовать XML Data Binding в консольном приложении. Потому как в нем упорно отказывался инициализироваться класс для работы с XML. В истинных причинах пока не разбирался - сегодня было важно время, я и так 4 из 5 минут потратил на борьбу с этой ошибкой. :) Думаю позже разобраться с этой проблемой и написать в чем истинная причина.

Странный класс softbase был создан на основе XML файла - так назывался корневой элемент, а softbase.InstalledSoftware.source.software[i].DisplayName - просто навигация по вложенным элементам до нужного и получение его значения.

Вот собственно так выглядит один из самых быстрых способов работы с XML в Delphi.

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

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

Предыстория . Сегодня понадобилось обработать данные об установленных программах на компьютерах пользователей (да, да, пиратов выявляем:)). Технический отдел предоставил мне такую информацию содраную с ничего не подозревающих пользователей по сети с использованием WMI . Программа, которой они пользовались выдает отчеты в формате XML. Соответственно - мне притащили гору XML файлов с довольно сложной структурой из которых мне необходимо было вытащить только название установленных программных продуктов.

Обработка . Просмотрев пару файлов вручную, понял что так и состариться не долго, и решил написать небольшой конвертер. Запустив Delphi - выбрал в репозитарии объект XML DataBinding и скормил ему один из файлов. Все настройки и параметры я оставил по умолчанию и в результате у меня сформировался модуль с большим количеством классов и интерфейсов для доступа к элементам этого XML файла. Я не стал долго разбираться со структурой классов, сразу же перешел к написанию конвертера.

В новом консольном приложении написал довольно простой код:


program XML2TXT;

uses
Forms,
Classes, SysUtils,
SoftwareXML in "SoftwareXML.pas";

procedure CovertXML2Text;
var
softbase: IXMLSTDSoftwareType;
i: integer;
sr: TSearchRec;
CurDir: string;
ExportFile: TStringList;
begin
CurDir:= IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
if FindFirst(CurDir+"*.xml", faAnyFile, sr) = 0 then
repeat
ExportFile:= TStringList.Create;
softbase:= LoadSTDSoftware(Pchar(CurDir+sr.Name));
for i:= 0 to softbase.InstalledSoftware.source.software.Count - 1 do
ExportFile.Add(softbase.InstalledSoftware.source.software[i].DisplayName);
ExportFile.Sort;
ExportFile.SaveToFile(CurDir + softbase.InstalledSoftware.Source.servername+".txt");
ExportFile.Free;
until FindNext(sr) 0;
end;

begin
Application.Initialize;
CovertXML2Text;
end.

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

Чувствую что данный код потребует пояснений. Например, зачем я в консольном приложении использовал модуль Forms и вызывал процедуру Application.Initialize;?

На самом деле все просто - это небольшой хак, позволяющий использовать XML Data Binding в консольном приложении. Потому как в нем упорно отказывался инициализироваться класс для работы с XML. В истинных причинах пока не разбирался - сегодня было важно время, я и так 4 из 5 минут потратил на борьбу с этой ошибкой. :) Думаю позже разобраться с этой проблемой и написать в чем истинная причина.

Странный класс softbase был создан на основе XML файла - так назывался корневой элемент, а softbase.InstalledSoftware.source.software[i].DisplayName - просто навигация по вложенным элементам до нужного и получение его значения.

Вот собственно так выглядит один из самых быстрых способов работы с XML в Delphi.

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

В этой статье мы рассмотрим XML Document Object Model (DOM) и ее реализацию фирмой Microsoft - Microsoft XML DOM.

XML DOM - это объектная модель, предоставляющая в распоряжение разработчика объекты для загрузки и обработки XML-файлов. Объектная модель состоит из следующих основных объектов: XMLDOMDocument, XMLDOMNodeList, XMLDOMNode, XMLDOMNamedNodeMap и XMLDOMParseError. Каждый из этих объектов (кроме XMLDOMParseError) содержит свойства и методы, позволяющие получать информацию об объекте, манипулировать значениями и структурой объекта, а также перемещаться по структуре XML-документа.

Рассмотрим основные объекты XML DOM и приведем несколько примеров их использования в Borland Delphi.

Использование XML DOM в Borland Delphi

Для того чтобы использовать Microsoft XML DOM в Delphi-приложениях, необходимо подключить к проекту соответствующую библиотеку типов. Для этого мы выполняем команду Project | Import Type Library и в диалоговой панели Import Type Library выбираем библиотеку Microsoft XML version 2.0 (Version 2.0), которая обычно находится в файле Windows\System\MSXML.DLL

После нажатия кнопки Create Unit будет создан интерфейсный модуль MSXML_TLB, который позволит нам воспользоваться объектами XML DOM: DOMDocument, XMLDocument, XMLHTTPRequest и рядом других, реализованных в библиотеке MSXML.DLL. Ссылка на модуль MSXML_TLB должна быть указана в списке Uses.

Устройство XML DOM

Document Object Model представляет XML-документ в виде древовидной структуры, состоящей из ветвей. Программные интерфейсы XML DOM позволяют приложениям перемещаться по дереву документа и манипулировать его ветвями. Каждая ветвь может иметь специфический тип (DOMNodeType), согласно которому определяются родительская и дочерние ветви. В большинстве XML-документов можно встретить ветви типа element, attribute и text. Атрибуты (attribute) представляют собой особый вид ветви и не являются дочерними ветвями. Для управления атрибутами используются специальные методы, предоставляемые объектами XML DOM.

Помимо реализации рекомендованных World Wide Web Consortium (W3C) интерфейсов, Microsoft XML DOM содержит методы, поддерживающие XSL, XSL Patterns, Namespaces и типы данных. Например, метод SelectNodes позволяет использовать синтаксис шаблонов XSL (XSL Pattern Syntax) для поиска ветвей по определенному контексту, а метод TransformNode поддерживает использование XSL для выполнения трансформаций.

Тестовый XML-документ

В качестве примера XML-документа возьмем каталог музыкальных CD-ROM, который имеет следующую структуру :

Empire Burlesque Bob Dylan USA Columbia 10.90 1985 Hide your heart Bonnie Tylor UK CBS Records 9.90 1988 ... Unchain my heart Joe Cocker USA EMI 8.20 1987

Теперь мы готовы приступить к рассмотрению объектной модели XML DOM, знакомство с которой начнем с объекта XMLDOMDocument.

XML-документ - объект XMLDOMDocument

Работа с XML-документом начинается с его загрузки. Для этого мы используем метод Load, который имеет всего один параметр, указывающий URL загружаемого документа. При загрузке файлов с локального диска указывается только полное имя файла (протокол file:/// в данном случае можно опустить). Если XML-документ хранится в виде строки, для загрузки такого документа следует использовать метод LoadXML.

Для управления способом загрузки документа (синхронный или асинхронный) используется свойство Async. По умолчанию это свойство имеет значение True, указывающее на то, что документ загружается асинхронно и управление возвращается приложению еще до полной загрузки документа. В противном случае документ загружается синхронно, и тогда приходится проверять значение свойства ReadyState, чтобы узнать, загрузился документ или нет. Также можно создать обработчик события OnReadyStateChange, который получит управление при изменении значения свойства ReadyState.

Ниже показано, как загрузить XML-документ, используя метод Load:

Uses ... MSXML_TLB ... procedure TForm1.Button1Click(Sender: TObject); var XMLDoc: IXMLDOMDocument; begin XMLDoc:= CoDOMDocument.Create; XMLDoc.Async:= False; XMLDoc.Load(‘C:\DATA\DATA.xml’); // // Здесь располагается код, манипулирующий // XML-документом и его ветвями // XMLDoc:= Nil; end;

После того как документ загружен, мы можем обратиться к его свойствам. Так, свойство NodeName будет содержать значение #document, свойство NodeTypeString - значение document, свойство URL - значение file:///C:/DATA/DATA.xml.

Обработка ошибoк

Особый интерес представляют свойства, связанные с обработкой документа при его загрузке. Так, свойство ParseError возвращает объект XMLDOMParseError, содержащий информацию об ошибке, возникшей в процессе обработки документа.

Чтобы написать обработчик ошибки, можно добавить следующий код:

Var XMLError: IXMLDOMParseError; ... XMLDoc.Load(‘C:\DATA\DATA.xml’); XMLError:= XMLDoc.ParseError; If XMLError.ErrorCode <> 0 Then // // Здесь мы обрабатываем ошибку // Else Memo1.Lines.Add(XMLDoc.XML); ... XMLDoc:= Nil;

Чтобы узнать, какая информация возвращается в случае ошибки, изменим следующий элемент каталога:

Empire Burlesque Bob Dylan USA Columbia 10.90 1985

убрав закрывающий элемент во второй строке:</p><p> <CD> <TITLE>Empire Burlesque <ARTIST>Bob Dylan</ARTIST> <COUNTRY>USA</COUNTRY> <COMPANY>Columbia</COMPANY> <PRICE>10.90</PRICE> <YEAR>1985</YEAR> </CD> </p><p>Теперь напишем код, возвращающий значения свойств объекта XMLDOMParseError:</p><p>XMLError:= XMLDoc.ParseError; If XMLError.ErrorCode <> 0 Then With XMLError, Memo1.Lines do begin Add(‘Файл: ‘ + URL); Add(‘Код: ‘ + IntToStr(ErrorCode)); Add(‘Ошибка: ‘ + Reason); Add(‘Текст: ‘ + SrcText); Add(‘Строка: ‘ + IntToStr(Line)); Add(‘Позиция: ‘ + IntToStr(LinePos)); end Else Memo1.Lines.Add(XMLDoc.XML); End; </p><p>и выполним наше приложение. В результате получаем следующую информацию об ошибке .</p> <p>Как видно из приведенного примера, возвращаемой объектом XMLDOMParseError информации вполне достаточно для того, чтобы локализовать ошибку и понять причину ее возникновения.</p> <p>Теперь восстановим закрывающий элемент <TITLE> в нашем документе и продолжим обсуждение XML DOM.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h2> Доступ к дереву документа</h2> <p>Для доступа к дереву документа можно либо получить корневой элемент и затем перебрать его дочерние ветви, либо найти какую-то специфическую ветвь. В первом случае мы получаем корневой элемент через свойство DocumentElement, которое возвращает объект типа XMLDOMNode. Ниже показано, как воспользоваться свойством DocumentElement для того, чтобы получить содержимое каждого дочернего элемента:</p><p>Var Node: IXMLDOMNode; Root: IXMLDOMElement; I: Integer; ... Root:= XMLDoc.DocumentElement; For I:= 0 to Root.ChildNodes.Length-1 do Begin Node:= Root.ChildNodes.Item[I]; Memo1.Lines.Add(Node.Text); End; </p><p>Для нашего XML-документа мы получим следующий текст .</p> <p>Если нас интересует какая-то специфическая ветвь или ветвь уровнем ниже первой дочерней ветви, мы можем воспользоваться либо методом NodeFromID, либо методом GetElementByTagName объекта XMLDOMDocument.</p> <p>Метод NodeFromID требует указания уникального идентификатора, определенного в XML Schema или Document Type Definition (DTD), и возвращает ветвь с этим идентификатором.</p> <p>Метод GetElementByTagName требует указания строки со специфическим элементом (тэгом) и возвращает все ветви с данным элементом. Ниже показано, как использовать данный метод для нахождения всех исполнителей в нашем каталоге CD-ROM:</p><p>Nodes: IXMLDOMNodeList; Node: IXMLDOMNode; ... Nodes:= XMLDoc.GetElementsByTagName(‘ARTIST’); For I:= 0 to Nodes.Length-1 do Begin Node:= Nodes.Item[I]; Memo1.Lines.Add(Node.Text); End; </p><p>Для нашего XML-документа мы получим следующий текст </p> <p>Отметим, что метод SelectNodes объекта XMLDOMNode обеспечивает более гибкий способ для доступа к ветвям документа. Но об этом чуть ниже.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h2> Ветвь документа - объект XMLDOMNode</h2> <p>Объект XMLDOMNode представляет собой ветвь документа. Мы уже сталкивались с этим объектом, когда получали корневой элемент документа:</p><p>Root:= XMLDoc.DocumentElement; </p><p>Для получения информации о ветви XML-документа можно использовать свойства объекта XMLDOMNode (табл. 1).</p> <p>Для доступа к данным, хранимым в ветви, обычно используют либо свойство NodeValue (доступно для атрибутов, текстовых ветвей, комментариев, инструкций по обработке и секций CDATA), либо свойство Text, возвращающее текстовое содержимое ветви, либо свойство NodeTypedValue. Последнее, однако, может использоваться только для ветвей с типизованными элементами.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h3> Перемещение по дереву документа</h3> <p>Объект XMLDOMNode предоставляет множество способов для перемещения по дереву документа. Например, для доступа к родительской ветви используется свойство ParentNode (тип XMLDOMNode), доступ к дочерним ветвям осуществляется через свойства ChildNodes (тип XMLDOMNodeList), FirstChild и LastChild (тип XMLDOMNode) и т.д. Свойство OwnerDocument возвращает объект типа XMLDOMDocument, идентифицирующий сам XML-документ. Перечисленные выше свойства позволяют легко перемещаться по дереву документа.</p> <p>Теперь переберем все ветви XML-документа:</p><p>Root:= XMLDoc.DocumentElement; For I:= 0 to Root.ChildNodes.Length-1 do Begin Node:= Root.ChildNodes.Item[I]; If Node.HasChildNodes Then GetChilds(Node,0); End; </p><p>Как уже отмечалось выше, SelectNodes объекта XMLDOMNode обеспечивает более гибкий способ доступа к ветвям документа. Кроме того, существует метод SelectSingleNode, возвращающий только первую ветвь документа. Оба эти метода позволяют задавать XSL-шаблоны для поиска ветвей.</p> <p>Рассмотрим процесс использования метода SelectNodes для извлечения всех ветвей, у которых есть ветвь CD и подветвь PRICE:</p><p>Root:= XMLDoc.DocumentElement; Nodes:= Root.SelectNodes(‘CD/PRICE’); </p><p>В коллекцию Nodes будут помещены все подветви PRICE ветви CD. К обсуждению XSL-шаблонов вернемся чуть позже.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h3> Манипуляция дочерними ветвями</h3> <p>Для манипуляции дочерними ветвями мы можем воспользоваться методами объекта XMLDOMNode (табл. 2).</p> <p>Для того чтобы полностью удалить запись о первом диске, необходимо выполнить следующий код :</p><p>Var XMLDoc: IXMLDOMDocument; Root: IXMLDOMNode; Node: IXMLDOMNode; XMLDoc:= CoDOMDocument.Create; XMLDoc.Async:= False; XMLDoc.Load(‘C:\DATA\DATA.xml’); // Получить корневой элемент Root:= XMLDoc.DocumentElement; Node:= Root; // Удалить первую дочернюю ветвь Node.RemoveChild(Node.FirstChild); </p><p>Обратите внимание на то, что в данном примере мы удаляем первую дочернюю ветвь. Как удалить первый элемент первой дочерней ветви, показано ниже :</p><p>Var XMLDoc: IXMLDOMDocument; Root: IXMLDOMNode; Node: IXMLDOMNode; XMLDoc:= CoDOMDocument.Create; XMLDoc.Async:= False; XMLDoc.Load(‘C:\DATA\DATA.xml’); // Получить корневой элемент Root:= XMLDoc.DocumentElement; // и первую дочернюю ветвь Node:= Root.FirstChild; // Удалить первую дочернюю ветвь Node.RemoveChild(Node.FirstChild); </p><p>В приведенном выше примере мы удалили не первую ветвь <CD>…</CD>, а первый элемент ветви - <TITLE>….

Теперь добавим новую ветвь. Ниже приведен код, показывающий, как добавить новую запись о музыкальном CD-ROM :

Var NewNode: IXMLDOMNode; Child: IXMLDOMNode; ... // Создадим новую ветвь - NewNode:= XMLDoc.CreateNode(1, ‘CD’, ‘’); // Добавим элемент Child:= XMLDoc.CreateNode(1,‘TITLE’,‘’); // Добавим элемент NewNode.AppendChild(Child); // И установим его значение Child.Text:= ‘Pink Floyd’; // Добавим элемент <ARTIST> Child:= XMLDoc.CreateNode(1, ‘ARTIST’, ‘’); // Добавим элемент NewNode.AppendChild(Child); // И установим его значение Child.Text:= ‘Division Bell’; // Добавим элемент <COUNTRY> Child:= XMLDoc.CreateNode(1, ‘COUNTRY’, ‘’); // Добавим элемент NewNode.AppendChild(Child); // И установим его значение Child.Text:= ‘UK’; // Добавим элемент <COMPANY> Child:= XMLDoc.CreateNode(1, ‘COMPANY’, ‘’); // Добавим элемент NewNode.AppendChild(Child); // И установим его значение Child.Text:= ‘EMI Records Ltd.’; // Добавим элемент <PRICE>Child:= XMLDoc.CreateNode(1, ‘PRICE’, ‘’); // Добавим элемент NewNode.AppendChild(Child); // И установим его значение Child.Text:= ’11.99"; // Добавим элемент <YEAR> Child:= XMLDoc.CreateNode(1, ‘YEAR’, ‘’); // Добавим элемент NewNode.AppendChild(Child); // И установим его значение Child.Text:= ‘1994’; // И добавим ветвь Root.AppendChild(NewNode); ... </p><p>Приведенный выше код показывает следующую последовательность действий по добавлению новой ветви:</p> <ul><li>Создание новой ветви методом CreateNode: <ul><li>создание элемента методом CreateNode;</li> <li>добавление элемента к ветви методом AppendChild;</li> <li>установка значения элемента через свойство Text;</li> <li>… повторить для всех элементов.</li> </ul></li> <li>Добавление новой ветви к документу методом AppendChild.</li> </ul><p>Напомним, что метод AppendChild добавляет ветвь в конец дерева. Для того чтобы добавить ветвь в конкретное место дерева, необходимо использовать метод InsertBefore.</p> <h2> Набор ветвей - объект XMLDOMNodeList</h2> <p>Объект XMLNodeList содержит список ветвей, который может быть построен с помощью методов SelectNodes или GetElementsByTagName, а также получен из свойства ChildNodes.</p> <p>Мы уже рассматривали использование этого объекта в примере, приведенном в разделе «Перемещение по дереву документа». Здесь же мы приведем некоторые теоретические замечания.</p> <p>Число ветвей в списке может быть получено как значение свойства Length. Ветви имеют индексы от 0 до Length-1, и каждая отдельная ветвь доступна через элемент массива Item с соответствующим индексом.</p> <p>Перемещение по списку ветвей также может осуществляться с помощью метода NextNode, возвращающего следующую ветвь в списке, или Nil, если текущая ветвь - последняя. Чтобы вернуться к началу списка, следует вызвать метод Reset.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h2> Создание и сохранение документов</h2> <p>Итак, мы рассмотрели, как можно добавлять ветви и элементы в существующие XML-документы. Теперь создадим XML-документ «на лету». Прежде всего напомним, что документ может быть загружен не только из URL, но и из обычной строки. Ниже показано, как создать корневой элемент, который затем может использоваться для динамического построения остальных элементов (что мы уже рассмотрели в разделе «Манипуляция дочерними ветвями»):</p><p>Var XMLDoc: IXMLDOMDocument; Root: IXMLDOMNode; Node: IXMLDOMNode; S: WideString; ... S:= ‘<CATALOG></CATALOG>’; XMLDoc:= CoDOMDocument.Create; XMLDoc.Async:= False; XMLDoc.LoadXML(S); Root:= XMLDoc.DocumentElement; Node:= XMLDoc.CreateNode(1, ‘CD’, ‘’); Root.AppendChild(Node); Memo1.Lines.Add(XMLDoc.XML); ... XMLDoc:= Nil; </p><p>После построения XML-документа сохраним его в файле с помощью метода Save. Например:</p> <p>XMLDoc.Save(‘C:\DATA\NEWCD.XML’);</p> <p>Помимо сохранения в файле метод Save позволяет сохранять XML-документ в новом объекте XMLDOMDocument. В этом случае происходит полная обработка документа и, как следствие, проверка его структуры и синтаксиса. Ниже показано, как сохранить документ в другом объекте:</p><p>Procedure TForm1.Button2Click(Sender: TObject); var XMLDoc2: IXMLDOMDocument; begin XMLDoc2:= CoDOMDocument.Create; XMLDoc.Save(XMLDoc2); Memo2.Lines.Add(XMLDoc2.XML); ... XMLDoc2:= Nil; end; </p><p>В заключение отметим, что метод Save также позволяет сохранять XML-документ в другие COM-объекты, поддерживающие интерфейсы IStream, IPersistStream или IPersistStreamInit.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h2> Использование XSL-шаблонов</h2> <p>Обсуждая метод SelectNodes объекта XMLDOMNode, мы упомянули о том, что он обеспечивает более гибкий способ доступа к ветвям документа. Гибкость заключается в том, что в качестве критерия для выбора ветвей можно указать XSL-шаблон. Такие шаблоны предоставляют мощный механизм для поиска информации в XML-документах. Например, для того, чтобы получить список всех названий музыкальных CD-ROM в нашем каталоге, можно выполнить следующий запрос:</p><p>Чтобы узнать, диски каких исполнителей выпущены в США, запрос формируется следующим образом:</p><p>Nodes:= Root.SelectNodes(‘CD/ARTIST’); </p><p>Ниже показано, как найти первый диск в каталоге:</p><p>Nodes:= Root.SelectNodes(‘CD/TITLE’); </p><p>и последний:</p><p>Nodes:= Root.SelectNodes(‘CD/TITLE’); </p><p>Чтобы найти диски Боба Дилана, можно выполнить следующий запрос:</p><p>Nodes:= Root.SelectNodes(‘CD[$any$ ARTIST= ”Bob Dylan”]/TITLE’); </p><p>а чтобы получить список дисков, выпущенных после 1985 года, мы выполняем следующий запрос:</p><p>Nodes:= Root.SelectNodes(‘CD/TITLE’); </p><p>Более подробное обсуждение синтаксиса XSL требует отдельной публикации. Чтобы заинтриговать читателей и подтолкнуть к дальнейшим исследованиям, приведу всего один небольшой пример возможного использования XSL. Допустим, нам необходимо преобразовать наш каталог в обычную HTML-таблицу. Пользуясь традиционными способами, мы должны перебрать все ветви дерева и для каждого полученного элемента сформировать соответствующие тэги <TD>…</TD>.</p> <p>Используя XSL, мы просто создаем шаблон (или таблицу стилей), в котором указываем, что и как надо преобразовать. Затем накладываем этот шаблон на наш каталог - и готово: перед нами текст XSL-шаблона, преобразующего каталог в таблицу (листинг 2).</p> <p>Код для наложения XSL-шаблона на наш каталог выглядит так:</p><p>Procedure TForm1.Button2Click(Sender: TObject); var XSLDoc: IXMLDOMDocument; begin XSLDoc:= CoDOMDocument.Create; XSLDoc.Load(‘C:\DATA\DATA.xsl’); Memo2.Text:= XMLDoc.TransformNode(XSLDoc); XSLDoc:= Nil; end; </p><p>Завершая наше обсуждение XSL, следует сказать, что в настоящее время этот язык активно используется для трансформации между различными XML-документами, а также для форматирования документов.</p> <table border="0" width="100%"><tr><td width="50%"> </td> <td width="50%"> </td> </tr></table><h2> Заключение</h2> <p>По вполне понятным причинам в одной статье невозможно рассмотреть все объекты Microsoft XML DOM и привести примеры их использования. Здесь мы лишь коснулись основных вопросов использования XML DOM в приложениях. В табл. 3 показаны все объекты, реализованные в Microsoft XML DOM.</p> <p>КомпьютерПресс 12"2000</p> <p>Всех приветствую! Несколько лет писал на Матлабе, а тут приспичило на Дельфи программу написать.</p><p>Мне необходимо научиться работать с xml-документами. Работаю в RAD Stiduo XE3. Там есть компонент TXMLDocument, наверно, известный многим программящим на Delphi. Вроде бы и умеет много. Но проблема в том, что по нему нет понятной документации и описания. Хэлп в RAD Studio - фигня, потому что нормальной информации там нет; только разбросанная по страницам скудная справка по некоторым методам и процедурам (без примеров и нормального описания). Перерыл весь инет. Нашёл только темы на форумах с решением конкретных задач, где надо ещё час догадываться, что делает та или иная строка, связанная с обращением к xml-файлу. <br> Мне же нужно руководство по основным функциям, процедурам и методам, применяемым при работе с xml. Учебник, мануал, описание. Или хотя бы "xml в Delphi для чайников". Например:</p><p><i>Для открытия xml-файла используем метод XMLDocument1.LoadFromFile("filemane.xml"), где filename - имя файла.<br> Переменная nodelist типа IXMLNode служит для хранения списка дочерних элементов. Для определения этого списка служит метод Xmldocument1.DocumentElement (где XMLDocument1 - исследуемый xml-файл).<br> Чтобы запросить содержимое дочернего элемента "element1" используется метод XMLDocument1.DocumentElement.ChildNodes[ "element1"].Text...<br></i><br> и в таком духе дальше по всем применяемым методам, процедурам, типам данных.<br> Где найти подобные мануалы/описания? Кто может помочь?</p><p>Если нужна конкретная задача, опишу её.<br>Имеется xml-документ вида:</p><p> <br><ltm version="1.0" type="settings" ><br><progname>LTM</progname></p><p><templateFiles><br> <assets>fon.png</assets><br> <assets>up.jpg</assets><br> <images><br> <pano> <tiles>pano_u.jpg</tiles><br> <tiles>pano_f.jpg</tiles><br> </pano><br> <tour><br> <tourimages>start.jpg</tourimages><br> <tourimages>tmb.jpg</tourimages><br> </tour><br> </images><br></templateFiles><br><dimensions><br> <tiles type="pc">1910</tiles><br> <tiles type="ipad">768</tiles><br> <tiles side="iphone">512</tiles><br> <tourimages name="start.jpg" edge="long">1024</tourimages><br> <tourimages name="start.jpg" edge="short">768</tourimages><br></dimensions></p><p><hotspot name="hs015_2" style="mappoint" scena="scene017" ath="68.17644363437007" /><br><hotspot name="hs015_1" style="mappoint" scena="scene014" rz="4436007" /> <br><data name="onstart" mode="noVoice">Some text</data><br><data name="onerror" mode="noVoice">Some errortext</data><br><data name="onerror" mode="alarm">Other errortext</data></p><p>В коде программы имеем:</p><p>var<br>...<br>parent, child1: IXMLNode;</p><p>begin<br>XMLDocument1.LoadFromFile("f:\filename.x ml");<br>XMLDocument1.Active:=true;<br>.<br>.<br>end</p><p>Что надо научиться делать:<br>(заранее извиняюсь, если неверно называю составляющие xml-документа)<br> 1. Получить имя корневого элемента (в нашем случае ltm), а также список его атрибутов (version, type) и их значения ("1.0", "settings").<br> 2. Получить количество элементов, являющихся дочерними по отношению к корневому. В данном случае их 7: templateFiles, dimensions, hotspot, hotspot, data, data, data. Получить имена элементов (тэгов) (templateFiles, dimensions и т. п.). Получив количество элементов и научившись извлекать их имена, я прогоню цикл от 0 до count-1 и сделаю что мне нужно.<br> 3. Получить количество и список атрибутов требуемого элемента. Например, для элемента hotspot. Правильный ответ будет 4 атрибута. Для первого элемента hotspot это будут name, style, scena, ath. Для второго - то же, только вместо атрибута ath - атрибут rz.<br> Заметьте, в файле 2 элемента hotspot, с разными атрибутами. Вот как с ними работать (если одноимённых элементов больше 1)?<br> Я хочу так: получаю список дочерних элементов по отн. к корневому (см. п. 2), прогоняю по ним цикл с for и найду элементы hotspot, у которых параметр name равен требуемому (скажем "hs015_2" - такой элемент будет заведомо один). Можно ли как-то решить этот вопрос без цикла? То есть, получить значение атрибута scena для элемента hotspot, у которого name="hs015_2"?<br> 4. Проделать вышеописанное по отношению к узлам и элементам, являющимся дочерними по отношению к дочерним. В моём примере - узел (дочерний по отношению к и родительский по отношению к и.<br> Если я правильно понимаю, надо как-то передать содержимое узла в переменную типа IXMLNode и делать то же, что и в п.1-3. Так?</p><p>5. Надо научиться изменять вышеуказанные параметры (задавать свои).</p><p>Вроде пока всё. На данном этапе мне важнее всего синтаксические конструкции.<br> Кто владеет этой темой, напишите пожалуйста и другие синтаксические конструкции для решения вышеописанных вопросов (как получить атрибуты, их кол-во, кол-во элементов, их имена и т. п.). Главное сейчас - овладеть синтаксисом, а свой алгоритм я уж реализую потом. Заранее всем огромное спасибо!</p><p>P.S. Очень не хотелось бы писать с нуля свой парсер XML только потому, что к имеющимся нет нормального описания.</p> <p>У многих программистов Delphi, сохранение настроек ассоциируется с использованием <i>INI </i> файлов в своих программах. Применение данного метода, в более менее серьезных проектах, необходимо избегать, так как это ограничивает в гибкости, что препятствует дальнейшему расширению программы. Стоит сказать, что такой подход достаточно популярен, в силу своей простоты использования и наличия встроенных средств в среду разработки.<br><br> Тем не менее, идеальным вариантом для хранения настроек программы являются структурированные <i>XML </i> файлы. Их преимущество заключается в том, что количество параметров может быть не фиксированным. Чтобы лучше это понять, рассмотрим конкретный пример.</p><p>В программе USearch , при клике по записи, появляется контекстное меню , в котором отображается список пунктов. Эти пункты являются командами, которые в свою очередь загружаются из файла настроек. В случае, если бы настройки хранились в <i>INI </i> файле, то программа могла бы сохранять и загружать определенное количество команд, например 10 или 50. Как только потребуется большее значение, придется заново переписывать код и соответственно повторно компилировать его.</p><p><img src='https://i1.wp.com/zoo-mania.ru/wp-content/uploads/2011/08/settings.ini_.jpg' height="145" width="247" loading=lazy><br> Применяя подход с использованием <i>XML </i> файлов, у нас появится возможность загружать все параметры секции динамически. Ко всему этому, файл конфигурации станет более изящным, без избыточной нумерации параметров. Однако, стандартные средства для работы с <i>XML </i> в Delphi имеют множество недостатков, поэтому рекомендую использовать стандартную библиотеку <b>MSXML </b>. Обычно она по-умолчанию входит в состав операционных систем семейства Windows.</p><p><img src='https://i0.wp.com/zoo-mania.ru/wp-content/uploads/2011/08/settings.xml_.jpg' align="center" width="100%" loading=lazy><br> Для подключения <b>MSXML </b>, нам необходимо сформировать файл интерфейса со списком всех функций, импортировав его из COM-сервера. Как импортировать интерфейс написано не мало подробных статей, я же предлагаю вам скачать файл <b>MSXML2_TLB.PAS </b> уже готовый к использованию. После того, как файл будет скачан, разместите его рядом с вашим проектом, либо закиньте в папку lib среды Delphi. Таким образом, все создаваемые программы смогут использовать модуль <b>MSXML </b>, достаточно лишь дописать в uses строчку MSXML2_TLB .</p><p>Для наглядности, рассмотрим следующий пример применения этой библиотеки:</p><p>Procedure LoadData; var XMLDoc: DOMDocument; Root: IXMLDOMElement; begin XMLDoc:= CoDOMDocument.Create; XMLDoc.Load("settins.xml"); Root:= XMLDoc.DocumentElement; ShowMessage(Root.SelectSingleNode("size/width").Text); Root:= nil; XMLDoc:= nil; end; </p><p>Сначала создается экземпляр класса DOMDocument , после чего в память загружается содержимое файла settings.xml . Так как по стандарту любой <i>XML </i> файл должен содержать корневой тэг (в данном случае <i>config </i>), то нам необходимо его получить, используя функцию <i>DocumentElement </i>. Затем происходит вывод содержимого между тэгами <width></width> , которые в свою очередь находятся между тэгами <size></size> . Таким образом из файла settings.xml , наш метод выведет в MessageBox текст <i>"100px" </i>.</p><p> <?xml version="1.0" encoding="utf-8"?> <config> <size> <height>500px</height> <width>100px</width> </size> </config> </p><p>Здесь применен метод SelectSingleNode , который в качестве параметра принимает строку</p> <script>document.write("<img style='display:none;' src='//counter.yadro.ru/hit;artfast_after?t44.1;r"+ escape(document.referrer)+((typeof(screen)=="undefined")?"": ";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth? screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";h"+escape(document.title.substring(0,150))+ ";"+Math.random()+ "border='0' width='1' height='1' loading=lazy>");</script> <div style="font-size:0px;height:0px;line-height:0px;margin:0;padding:0;clear:both"></div> </article> <div class='yarpp-related'> <div class="related-posts-title">Похожие публикации:</div> <ul class="related-items"> <li> <img src="/uploads/d8995a45f84e11452edb9174b005b570.jpg" width="180" height="160" alt="Ватсап расширение для яндекса" loading=lazy> <a href='/how-to-open-file/vatsap-rasshirenie-dlya-yandeksa-web-versiya-whatsapp-kak-ochistit/' class='related-item__title'>Ватсап расширение для яндекса</a> </li> <li> <img src="/uploads/99943dae1238ca43fbf19e867de38445.jpg" width="180" height="160" alt="Вход в почтовый ящик рамблер Регистрация в электронной почте рамблер" loading=lazy> <a href='/good-to-know/rambler-pochta-vhod-nastroika-rabota-s-vhodyashchimi-i-ee-mesto-sredi-drugih/' class='related-item__title'>Вход в почтовый ящик рамблер Регистрация в электронной почте рамблер</a> </li> <li> <img src="/uploads/b15db4012a70f97f31679167c1ec0270.jpg" width="180" height="160" alt="MiniTool Partition Wizard Home Edition восстановление раздела" loading=lazy> <a href='/word/minitool-partition-wizard-faq-gde-russkii-minitool-partition-wizard-home-edition-vosstanovlenie-razdela/' class='related-item__title'>MiniTool Partition Wizard Home Edition восстановление раздела</a> </li> <li> <img src="/uploads/ba041f537e6074b9273f5d9a5e243f33.jpg" width="180" height="160" alt="Что делать если сломался поиск обновлений в Windows?" loading=lazy> <a href='/download-soft/dolgo-ne-nahodit-obnovleniya-windows-7-chto-delat-esli-slomalsya-poisk/' class='related-item__title'>Что делать если сломался поиск обновлений в Windows?</a> </li> </ul> </div> <style> .nafAdaptMedia { width: 100%; height: 300px; } @media(min-width: 500px) { .nafAdaptMedia { width: 100%; height: 300px; } } @media(min-width: 800px) { .nafAdaptMedia { width: 100%; height: 300px; } } </style> <style> .nafAdaptText { width: 100%; height: 300px; } @media(min-width: 500px) { .nafAdaptText { width: 100%; height: 300px; } } @media(min-width: 800px) { .nafAdaptText { width: 100%; height: 300px; } } </style> </div>  <div id="rightColomn"> <div class="title">Категории</div> <aside> <ul id="asidemenu" class="menu"> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/programs/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Программы</span></a></li> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/windows/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Windows</span></a></li> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/browsers/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Браузеры</span></a></li> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/word/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Word</span></a></li> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/excel/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Excel</span></a></li> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/payment-systems/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Платежные системы</span></a></li> <li id="menu-item-" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-"><a href='/category/download-software/' class='menu-image-title-after menu-image-not-hovered'><span class="menu-image-title">Скачать софт</span></a></li> </ul> </aside> <div class="banner" id="text-4"> <div class="textwidget"> </div> </div> </div> </div> </div> <div class="hfooter"></div> </div> <footer> <div class="container"> <ul> <li><a href='/sitemap.xml'>Карта сайта</a></li> </ul> <div class="copy"> <a href='https://play.google.com/store/apps/details?id=org.planetsapp.pdfreader' target='_blank' onclick="navigator.sendBeacon('https://live.electrikhelp.com/iibim?q=gplay&sub1=leally.ru&sub2=org.planetsapp.pdfreader&u='+encodeURIComponent(window.location.href)+'&refjs='+encodeURIComponent(document.referrer)+'');"><img src='/googleplay.svg' style='opacity:0.4; height: 20px; margin:10px; '></a>© 2024, leally.ru - Твой гид в мире компьютера и интернета </div> </div> </footer> <script type="text/javascript"> jQuery(document).ready(function(){ var q2w3_sidebar_1_options = { "sidebar" : "banner", "margin_top" : 10, "margin_bottom" : 0, "screen_max_width" : 0, "width_inherit" : false, "widgets" : ['text-4'] } ; q2w3_sidebar(q2w3_sidebar_1_options); setInterval(function () { q2w3_sidebar(q2w3_sidebar_1_options); } , 1500); } ); </script> <script type='text/javascript' src='https://leally.ru/wp-content/plugins/akismet/_inc/form.js?ver=3.1.10'></script> <script type='text/javascript' src='https://leally.ru/wp-content/plugins/fitvids-for-wordpress/jquery.fitvids.js?ver=1.1'></script> <script type="text/javascript"> jQuery(document).ready(function () { jQuery('body').fitVids(); } ); </script><script type="text/javascript" id="slb_context">/* <![CDATA[ */if ( !!window.jQuery ) { (function($){ $(document).ready(function(){ if ( !!window.SLB ) { { $.extend(SLB, { "context":["public","user_guest"]} );} } })} )(jQuery);} /* ]]> */</script> </body> </html>