14. XML Library

New in version Global: 5.5.0.3950 ms 7

Подключение библиотеки XML в скрипте
uses
  XML;
begin
  // Пишите ваш код здесь.
end;

Актуальная версия модуля работает с XML посредством библиотеки LibXml2.dll.

Note

Библиотека libxml2.dll имеет зависимости от библиотек iconv.dll и zlib1.dll.

Note

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

14.1. Краткое руководство

Note

Данный API широко использует понятие Node(Узел). К узлам относятся XML-Element-ы, текстовые узлы и коментарии.

14.1.1. Разбор XML

Разобрать можно файл *.xml, или строку содержащую XML (CreateXmlDocFromFile, CreateXmlDocFromString). Это первое что следует сделать начав работу с XML - у вас появится экземпляр XML-документа с которым можно работать.

14.1.2. Навигация по документу

Этот процесс начинается с получения корневого узла (TbtkXmlDoc.Root). Имея узел - можно обратиться к его ближайшим узлам (TbtkXmlNodeCursor.Parent, TbtkXmlNodeCursor.NextSibling, TbtkXmlNodeCursor.PrevSibling, TbtkXmlNodeCursor.Child), таким образом реализуется возможность обойти документ.

Пример обхода узлов XML-документа
<pascal>
uses
  XML;

  function EnumNodes(ANode: TbtkXmlNodeCursor; APrefix: string): string;
  begin
    Result := '';
    while Assigned(ANode) do
    begin
      Result := Result + APrefix +
        ANode.Name + #13 + EnumNodes(ANode.Child, APrefix+'    ');
      ANode := ANode.NextSibling;
    end;
  end;

begin
  doc := CreateXmlDocFromString('
    <root>
      <sub1/><sub2/>
      <sub3>
        <sub31/>
        <sub32><sub321/><sub322/><sub323/></sub32>
      </sub3>
    </root>');
  ShowMessage(EnumNodes(doc.Root, ''));
end;
</pascal>
Результат выполнения примера.
root
    text
    sub1
    sub2
    text
    sub3
        text
        sub31
        text
        sub32
            sub321
            sub322
            sub323
        text
    text

14.1.3. Копирование узлов

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

Пример работы XPath, Add* и канонизации
<pascal>
uses
  XML;
begin
  structure := CreateXmlDocFromString('
  <xml>
    <emplyer name="ООО Битек">
      <unit name="отд. Внедрения"><employee name="Иванов Иван"/></unit>
      <unit name="отд. Системный"><employee name="Петров Пётр"/></unit>
      <unit name="отд. Продаж"><employee name="Сидоров Сидор"/></unit>
    </emplyer>
  </xml>');

  empList := CreateXmlDocFromString('<xml/>');
  staff := structure.CreateXPathContext.FindNodes('//employee');

  for i := 0 to staff.Count - 1 do
    empList.Root.AddChild(staff.Nodes[i]);

  ShowMessage(empList.C14nCanonicalize(False));
end;
</pascal>
Результат выполнения примера
<xml><employee name="Иванов Иван"></employee><employee name="Петров Пётр"></employee><employee name="Сидоров Сидор"></employee></xml>

14.1.5. Поиск узлов

Если документ большой, а критерии отбора сложные - перебор узлов может стать непростой задачей - XPath-запросы гарантированно сделают её значительно проще и прозрачнее.

14.1.6. Канонизация XML

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

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

Note

Узел канонического представителя документа не обязательно будет каноничен. Если вам требуется текст канонизированного узла, то нужно проводить канонизацию именно узла!

<pascal>
uses
  XML;
begin
  doc := CreateXmlDocFromString('
  <xml xmlns:ns1="http://namespace.ru/ns1">
    <sub1/>
  </xml>');

  sub1Content := doc.CreateXPathContext.FindNodes('(//.|//@*|//namespace::*)[ancestor-or-self::sub1]');

  ...
doc.C14nCanonicalize(False)
<xml xmlns:ns1="http://namespace.ru/ns1">
    <sub1></sub1>
  </xml>
doc.C14nCanonicalize(False, sub1Content)
<sub1 xmlns:ns1="http://namespace.ru/ns1"></sub1>

14.2. Методы модуля

14.2.1. Документ XML

CreateEmptyXmlDoc(): TbtkXmlDoc

Создать пустой XML-документ.

Return type:TbtkXmlDoc
CreateXmlDocFromFile(FileName: String): TbtkXmlDoc

Создать XML-документ, загрузив его из файла.

Warning

Файл должен быть в кодировке UTF8.

Parameters:FileName (String) – путь к XML-файлу
Return type:TbtkXmlDoc
CreateXmlDocFromString(Xml: String): TbtkXmlDoc

Создать Xml-документ, загрузив его из текста.

Parameters:Xml (String) – текст XML-документа
Return type:TbtkXmlDoc

14.3. Классы модуля

14.3.1. TbtkXmlDoc

class TbtkXmlDoc

Экземпляр XML-документа.

CreateXPathContext(): TbtkXPathContext

Создать новый контекст выполнения XPath-запросов. Запросы будут выполняться по узлам данного документа.

Return type:TbtkXPathContext
C14nCanonicalize(Exclusive: Boolean[; Content: TbtkXmlNodeSet; WithComments: Boolean = True]): String

Выполнить C14N-канонизацию документа.

Parameters:
  • Exclusive (Boolean) – Режим выполнения канонизации. В случае True - будет использоваться Exclusive алгоритм.
  • Content (TbtkXmlNodeSet) – Множество узлов подлежищих канонизации. Ниодин узел не включённый в этот набор не попадёт в итоговый XML.
  • WithComments (Boolean) – Флаг указывает включать ли коментарии в итоговый XML.
Return type:

String

SetRootNode(NewRoot: TbtkXmlNodeCursor[; Recursive: Boolean = True])

Устанавливает копию узла корневым узлом документа.

Parameters:
  • NewRoot (TbtkXmlNodeCursor) – Узел по образу которого будет создан новый корневой узел документа.
  • Recursive (Boolean) – True - Копирование узла NewNode будет полным(рекурсивным), иначе - вложенные узлы копироваться не будут.
Root(): TbtkXmlNodeCursor

Корневой узел документа

Return type:TbtkXmlNodeCursor
ToString(): String

XML описывающий данный документ.

Return type:String
Пример работы TbtkXmlDoc.ToString.
<pascal>
uses
  XML;
begin
  doc := CreateXmlDocFromString('
  <root xmlns:ns1="http://exaple.ru/scheme#test" >
    <sub1></sub1><sub2/>
    <sub3 id = "foo">
      <sub31/>
      <sub32><ns1:sub321/><sub322/><sub323/></sub32>
    </sub3>
  </root>');
  ShowMessage(doc.ToString);
end;
</pascal>
Результат выполнения примера
<?xml version="1.0"?>
<root xmlns:ns1="http://exaple.ru/scheme#test">
    <sub1/><sub2/>
    <sub3 id="foo">
      <sub31/>
      <sub32><ns1:sub321/><sub322/><sub323/></sub32>
    </sub3>
  </root>

14.3.2. TbtkXPathContext

class TbtkXPathContext

Объект выполнения XPath-запросов. Подробнее о XPath можно прочесть на W3C. Также полезным будет прочесть XPath Tutorial.

В существующей версии данного модуля: XPath предлагается эксплуатировать как поисковую машину - искать интересующие узлы XML-документа не перебором от Root-а, а таргетированно, лаконичным запросом.

FindNode(XPath: String[; NullAllowed: Boolean = False]): TbtkXmlNodeCursor

Метод предназначен для выполнения запроса на поиск единственного узла.

Parameters:
  • XPath (String) – Текст XPath-запроса.
  • NullAllowed (Boolean) –

    Флаг говорит что запрос не обязательно вернёт узел. При выставленном флаге, если запрос не вернул ни одного узла:

    • метод не станет возбуждать исключение.
    • метод вернёт nil.
Return type:

TbtkXmlNodeCursor

Raises:
  • EbtkXPathError – XPath-запрос не на получение узлов
  • EbtkXPathError – XPath-запрос вернул больше одного узла
  • EbtkXPathError – XPath-запрос не соотвутствует ниодному узлу (при NullAllowed=False)
FindNodes(XPath: String): TbtkXmlNodeSet

Метод предназначен для выполнения запроса на поиск узлов.

Parameters:XPath (String) – Текст XPath-запроса.
Return type:TbtkXmlNodeSet
Raises:EbtkXPathError – XPath-запрос не на получение узлов
AddVariable(Name: String; Value: TbtkXmlNodeSet)

Определить переменную доступную в последующих XPath-запросах.

Parameters:
  • Name (String) – Наименование переменной
  • Value (TbtkXmlNodeSet) – Множество узлов представленное данной переменной в запросах
AddNamespace(Prefix, Ref: String)

Определить пространство имён доступное в последующих XPath-запросах. Можно будет искать узлы описанные в схеме данных данного пространства имён.

Parameters:
  • Prefix (String) – Префикс простанства имён который можно будет использовать в последующих запросах.
  • Ref (String) – Ссылка на схему данных определяющую указанное пространство имён.
xpath.AddNamespace('xades', 'http://uri.etsi.org/01903/v1.3.2#');
xpath.FindNode('//xades:Cert[1]');

14.3.3. TbtkXmlNodeCursor

class TbtkXmlNodeCursor

Узел XML-документа.

Name: String

Имя узла (тэга).

Return type:String
Пример использования
doc := CreateDocFromString('<xml></xml>');
if doc.Root.Name = 'xml' then
  ShowMessage('Всё верно.');
Attributes: String

Индексное свойство. Получить/задать значение атрибута XML-узла. Индексное свойство - в квадратных скобках указывается наименование интересующего атрибута строкой.

Parameters:Name (String) – Наименование атрибута узла
Return type:String
Пример использования
<pascal>
uses
  XML;
begin
  doc := CreateXmlDocFromString('<root existing="test"/>');
  doc.Root.Attributes['newOne'] := 'new ' + doc.Root.Attributes['existing'];
  ShowMessage(doc.ToString);
end;
</pascal>
Результат выполнения примера
<?xml version="1.0"?>
<root existing="test" newOne="new test"/>
OuterText: String

Получить XML-текст данного узла (со всеми подузлами и атрибутами).

Return type:String
Text: String

Получить/задать текст содержащийся в данном узле (со всеми подузлами). Результат - сумма всех текстовых подузлов данного узла.

Return type:String
Пример использования
ShowMessage(node.Text);
node.Text := 'new text. nested nodes are droped';
NextSibling: TbtkXmlNodeCursor

Узел следующий за данным. Если такового нет - nil.

Return type:TbtkXmlNodeCursor: TbtkXmlNodeCursor
PrevSibling: TbtkXmlNodeCursor

Узел предшествующий данному. Если такового нет - nil.

Return type:TbtkXmlNodeCursor
Child: TbtkXmlNodeCursor

Первый вложенный узел. Если такового нет - nil.

Return type:TbtkXmlNodeCursor
Parent: TbtkXmlNodeCursor

Родительский узел. Или nil, если его нет.

Return type:TbtkXmlNodeCursor
AddSibling(Node: TbtkXmlNodeCursor[; Recusive: Boolean = True]): TbtkXmlNodeCursor

Копия переданного узла будет добавлена в тот же список узлов что и данный.

Parameters:
  • Node (TbtkXmlNodeCursor) – Узел копия которого будет добавлена.
  • Recusive (Boolean) – Режим копирования переданного узла.
Returns:

Интегрированная в структуру документа копия узла Node.

Return type:

TbtkXmlNodeCursor

AddNextSibling(Node: TbtkXmlNodeCursor[; Recusive: Boolean = True]): TbtkXmlNodeCursor

Копия переданного узла будет добавлена следующим узлом по отношению к данному.

Parameters:
  • Node (TbtkXmlNodeCursor) – Узел копия которого будет добавлена.
  • Recusive (Boolean) – Режим копирования переданного узла.
Returns:

Интегрированная в структуру документа копия узла Node.

Return type:

TbtkXmlNodeCursor

AddPrevSibling(Node: TbtkXmlNodeCursor[; Recusive: Boolean = True]): TbtkXmlNodeCursor

Копия переданного узла будет добавлена как предыдущий узел по отношению к данному.

Parameters:
  • Node (TbtkXmlNodeCursor) – Узел копия которого будет добавлена.
  • Recusive (Boolean) – Режим копирования переданного узла.
Returns:

Интегрированная в структуру документа копия узла Node.

Return type:

TbtkXmlNodeCursor

AddChild(Node: TbtkXmlNodeCursor[; Recusive: Boolean = True]): TbtkXmlNodeCursor

Копия переданного узла будет добавлена в конец списка вложенных узлов.

Parameters:
  • Node (TbtkXmlNodeCursor) – Узел копия которого будет добавлена.
  • Recusive (Boolean) – Режим копирования переданного узла.
Returns:

Интегрированная в структуру документа копия узла Node.

Return type:

TbtkXmlNodeCursor

14.3.4. TbtkXmlNodeSet

class TbtkXmlNodeSet

Набор узлов. Как правило это результат выполнения поискового XPath-запроса.

Count: Integer

Количество узлов в данном наборе.

Return type:Integer
Nodes: TbtkXmlNodeCursor

Индексное свойство. Возвращает i-тый узел в наборе.

Parameters:Index (Integer) – индекс узла в наборе
Return type:TbtkXmlNodeCursor
Raises:EbtkXPathOutOfIndex – Index вне диапазона допустимых значений (0 >= Index > Count)