DOCUMENT OBJECT MODEL - ОБЪЕКТНАЯ МОДЕЛЬ XML-ДОКУМЕНТА

Document Object Model (DOM) представляет XML-документ в виде создаваемого в памяти дерева объектов (узлов), определяющих структуру XML. Создание дерева объектов в памяти является удобным способом работы с данными, но ограничивается ее доступным объемом. Таким образом, применение DOM отлично подходит при работе с небольшими XML документами.

XML-документ в ABL DOM представляется объектом X-DOCUMENT.

DEF VAR hDocument AS HANDLE  NO-UNDO.
CREATE X-DOCUMENT hDocument.

XML-узлы, представляются объектами X-NODEREF. 

DEFINE VARIABLE hNode AS HANDLE NO-UNDO.
CREATE X-NODEREF hNode.

XML-узлы разделяются по типу. Каждому XML-узлу указывается его тип, который определяет его характеристики и функциональность. Различаются следующие типы узлов:

  • ATTRIBUTE;
  • CDATA-SECTION;
  • COMMENT;
  • DOCUMENT-FRAGMENT;
  • ELEMENT;
  • ENTITY-REFERENCE;
  • PROCESSING-INSTRUCTION;
  • TEXT.

В качестве примера, рассмотрим XML-документ test.xml:

<?xml version="1.0" encoding="windows-1251"?>
<customers>
   <!-- Юридические лица -->
   <corporation>
     <name><![CDATA[ООО "Ivanov & Co"]]></name>
     <accounts>
        <account currency="810">40702810000000000001</account>
        <account currency="840">40702840000000000001</account>
     </accounts>
   </corporation>
</customers>

В DOM данный документ представляется следующим деревом объектов: 

 DOM.jpg

Каждый узел имеет своего единственного "родителя" (узел, располагающийся непосредственно над ним). Родительские узлы, в свою очередь, обладают так называемыми дочерними узлами (узлами, расположенными непосредственно под ними). У одного "родителя" может быть несколько дочерних узлов, при этом, каждый из них имеет свой порядковый номер начиная с 1.

На основе таких родительско-дочерних связей и формируется DOM структура XML-документа.

Стоит отметить, что атрибуты (узлы с типом ATTRIBUTE) не являются ни чьими дочерними или родительскими узлами, а относятся непосредственно к узлу элементу (узел с типом ELEMENT).

После завершения работы все созданные объекты должны быть удалены.

DELETE OBJECT hDocument.
DELETE OBJECT hNode.

Работа с XML-документом осуществляется с помощью атрибутов и методов объектов X-DOCUMENT и X-NODEREF.

x-handle [:attribute | :method]

Атрибуты X-DOCUMENT:

Атрибут Тип данных
Доступ Описание
HANDLE HANDLE чтение handle объекта XML-документа
NAME СHARACTER чтение/запись Имя источника XML-документа, например имя xml-файла.
ENCODING СHARACTER чтение/запись Определяет текстовую кодировку XML. Задает значение атрибута encoding пролога формируемого XML-докумета.
SCHEMA-PATH СHARACTER чтение/запись Список каталогов содержащих DTD
NONAMESPACE-SCHEMA-LOCATION СHARACTER чтение/запись Определяет расположение XML-схемы валидации формируемого XML-документа
SUPPRESS-NAMESPACE-PROCESSING LOGICAL чтение/запись
NAMESPACE-URI СHARACTER чтение/запись URI пространства имен
NAMESPACE-PREFIX СHARACTER чтение/запись Префикс пространства имен
NUM-CHILDREN INTEGER чтение Количество узлов в структуре XML-документа
UNIQUE-ID INTEGER чтение Уникальный ID объекта в рамках сессии
SYSTEM-ID CHARACTER чтение
PUBLIC-ID CHARACTER чтение
TYPE СHARACTER чтение Тип указателя. Значение "X-DOCUMENT"
SUBTYPE СHARACTER чтение Значение "DOCUMENT"

Методы X-DOCUMENT:

Метод Описание
ADD-SCHEMA-LOCATION() Задает расположение XML-схемы.
APPEND-CHILD() Добавляет дочерний узел в структуру XML-документа.
CREATE-NODE() Создает узел.
CREATE-NODE-NAMESPACE() Создает элемент определяющий пространство имен XML-документа.
GET-CHILD() Возвращает дочерний узел по его порядковому номеру. Нумерация узлов начинается с 1.
GET-DOCUMENT-ELEMENT() Возвращает корневой элемент XML-документа.
IMPORT-NODE() Импортирует узел из другого XML-документа
INITIALIZE-DOCUMENT-TYPE() Создает новый XML-документ согласно описанию DTD.
INSERT-BEFORE() Добавляет дочерний узел в структуру документа после указываемого.
LOAD() Загружает XML-документ в память для последующей работы с ним как с объектом X-DOCUMENT. 
REMOVE-CHILD() Открепляет узел и все его поддерево из структуры XML-документа. Сам узел при этом не удаляется из памяти
REPLACE-CHILD() Заменяет узел новым. При этом старый узел не удаляется из памяти, а просто открепляется от структуры XML-документа.
SAVE() Осуществляет формирование XML-документа из объекта X-DOCUMENT.

 

ADD-SCHEMA-LOCATION(targetNamespace, location) - данный метод определяет расположение XML-схемы валидации XML-документа посредством пространства имен и физического расположения файла XML-схемы.

  • targetNamespace - пространство имен, значение CHARACTER типа;
  • location - значение CHARACTER типа, определяющее расположение файла XML-схемы.

APPEND-CHILD(x-node-handle) - добавляет существующий узел как последний дочерний узел в структуре XML задаваемого родительского узла. Другими словами данный метод осуществляет размещение существующего узла, открепленного раннее от структуры XML, или созданного с помощью методов CREATE-NODE(), CREATE-NODE-NAMESPACE() или CLONE-NODE().

  • x-node-handle - handle X-NODREF объекта добавляемого узла.

CREATE-NODE(x-node-handle, name, type) - создает узел в текущем XML-документе.

  • x-node-handle - handle X-NODREF объекта, в который будет записан указатель создаваемого нового узла.
  • name - имя создаваемого узла, тип CHARACTER;
  • type - SUBTYPE создаваемого элемента, тип CHARACTER.

CREATE-NODE-NAMESPACE(x-node-handle, namespace-uri, qualified-name, type) - задает пространство имен документа. Может быть заданно как в простом виде - y, так и в составном - x:y.

  • x-node-handle - handle X-NODREF объекта, в который будет записан указатель создаваемого нового узла;
  • namespace-uri - Uniform Resource Identifier (URI) пространства имен, CHARACTER типа;
  • qualified-name - 
  • type - SUBTYPE узла, может принимать значение ELEMENT или ATTRIBUTE.

GET-CHILD(x-node-handle, index) - возвращает handle дочернего узла с порядковым номером index.

  • x-node-handle - handle возвращаемого узла;
  • index - порядковый номер узла.

GET-DOCUMENT-ELEMENT(x-node-handle) - возвращает handle X-NODEREF корневого элемента XML-документа.

  • x-node-handle - handle корневого элемента.

IMPORT-NODE(x-node, x-source-node, deep) - данный метод осуществляет импорт узла из другого XML-документа, но не размещает его в структуре XML. После того как новый узел импортирован, его необходимо включить в структуру XML с помощью методов APPEND-CHILD() или INSERT-BEFORE().

  • x-node - handle предварительно созданного X-NODREF объекта, в который будет осуществляться импорт;
  • x-source-nodehandle импортируемого X-NODREF объекта;
  • deep - значение LOGICAL типа, определяющее осуществлять импорт всего поддерева элемента (TRUE) или импортировать только непосредственно сам элемент (FALSE). Значением по умолчанию является FALSE.

INSERT-BEFORE(x-ref-handle1, x-ref-handle2) - осуществляет добавление узла в структуру XML как дочернего по отношению к тому узлу, чей метод вызывается и размещаемого после указываемого другого дочернего узла этого же родителя. Если узел, за которым должен быть размещен добавляемый элемент не указан, то он будет последним дочерним узлом.

  • x-ref-handle1handle объекта X-NODREF имеющегося в структуре узла, за которым необходимо разместить добавляемый в структуру узел;
  • x-ref-handle2 - handle объекта X-NODREF добавляемого узла. Данный узел должен быть предварительно создан.

LOAD(mode  { file | memptr | longchar }, validate) - осуществляет загрузку XML-документа из указываемого источника в память, разбирает его и формирует X-DOCUMENT для последующей работы с ним.

  • mode - значение CHARACTER типа, определяющие тип источника XML-документа. Может принимать следующие значения: "FILE", "MEMPTR", или "LONGCHAR";
  • { file | memptr | longchar } - идентификатор источника данных. Для файла - это его полный или относительный путь, для переменных  - идентификатор переменной и т.д;
  • validate - значение LOGICAL типа, определяющие осуществлять валидацию загружаемого XML-документа (TRUE), или не осуществлять ее (FALSE).

REMOVE-CHILD(x-node-handle) - открепляет узел и все его поддерево от структуры XML-документа. Сам узел при этом не удаляется, а остается в памяти.

  • x-node-handle - handle X-NODREF объекта открепляемого узла.

REPLACE-CHILD(new-handle, old-handle) - осуществляет замещение одного узла другим. При этом замещаемый узел только открепляется от структуры XML-документа, а не удаляется. Если замещающий узел находится в структуре XML-документа, то он первоначально открепляется от документа, а после прикрепляется на место замещаемого.

  • new-handle - handle X-NODREF объекта замещающего узла;
  • old-handle - handle X-NODREF объекта замещаемого узла.

SAVE(mode, { file | stream | stream-handle | memptr | longchar }) - осуществляет формирование и вывод текста XML-документа из X-DOCUMENT.

  • mode - значение CHARACTER типа, определяющие тип приемника XML-документа. Может принимать следующие значения: "FILE", "STREAM", "STREAM-HANDLE", "MEMPTR", или "LONGCHAR";
  • { file | stream | stream-handle | memptr | longchar } - определение приемника XML-документа.

 

Атрибуты X-NODEREF:

Атрибут Тип данных Доступ Описание
ATTRIBUTE-NAMES CHARACTER чтение Содержит список имен атрибутов элемента с разделителем запятая. Если элемент не имеет атрибутов значение - "" (пустая строка).
CHILD-NUM CHARACTER Чтение Порядковый номер узла среди своих родственников. Родственными узлами являются узлы принадлежащее одному родителю. Такие узлы нумеруются начиная с 1.  Если узел не является  дочерним - значение ?
HANDLE HANDLE чтение Содержит указатель на объект узла.
INSTANTIATING-PROCEDURE HANDLE чтение Содержит указатель процедуры, в которой данный узел был объявлен.
LOCAL-NAME
NAME CHARACTER чтение/запись Имя узла
NAMESPACE-PREFIX СHARACTER чтение/запись Префикс пространства имен
NAMESPACE-URI СHARACTER чтение/запись URI пространства имен
NODE-VALUE СHARACTER чтение/запись Возвращает и устанавливает значение узла
NUM-CHILDREN INTEGER чтение Количество дочерних элементов
OWNER-DOCUMENT  HANDLE чтение Содержит указатель на X-DOCUMENT,  к которому относится узел
SUBTYPE СHARACTER чтение Тип узла. Возможны следующие значения:
  • ATTRIBUTE;
  • CDATA-SECTION;
  • COMMENT;
  • DOCUMENT-FRAGMENT;
  • ELEMENT;
  • ENTITY-REFERENCE;
  • PROCESSING-INSTRUCTION;
  • TEXT.
TYPE СHARACTER чтение Тип указателя. Значение "X-NODEREF" 
UNIQUE-ID INTEGER чтение Уникальный ID узла в рамках XML-документа

Методы X-NODEREF:

Метод Описание
APPEND-CHILD() Добавляет узел в конец XML-документа или другого узел
CLONE-NODE() Осуществляет клонирование существующего узла
DELETE-NODE() Удаляет узел
GET-ATTRIBUTE() Возвращает значение указанного атрибута элемента
GET-ATTRIBUTE-NODE() Возвращает handle указанного атрибута элемента
GET-CHILD() Возвращает handle дочернего узла
GET-PARENT() Возвращает handle родительского узла
INSERT-BEFORE() Добавляет узел в структуру документа после указываемого другого дочернего узла того же родителя.
LONGCHAR-TO-NODE-VALUE() Присваивает значение LONGCHAR типа узлу XML
MEMPTR-TO-NODE-VALUE() Присваивает значение MEMPTR типа узлу XML
NODE-VALUE-TO-LONGCHAR() Преобразовывает значение NODE-VALUE в LONGCHAR тип 
NODE-VALUE-TO-MEMPTR() Преобразовывает значение NODE-VALUE в MEMPTR тип
NORMALIZE()
REMOVE-ATTRIBUTE() Удаляет указываемый атрибут элемента
REMOVE-CHILD() Открепляет узел и все его поддерево из структуры XML-документа. Сам узел при этом не удаляется из памяти
REPLACE-CHILD() Заменяет узел другим узлом в структуре XML-документа. Заменяемый узел при этом не удаляется из памяти.
SET-ATTRIBUTE() Добавляет атрибут элементу.
SET-ATTRIBUTE-NODE() Связывает указываемый атрибут с текущим элементом

 

CLONE-NODE(x-node-handle, deep) - осуществляет клонирование текущего узла.

  • x-node-handle - handle предварительно созданного X-NODREF объекта, в который будет осуществляться клонирование;
  • deep - значение LOGICAL типа, отражающее клонировать все дерево узла (TRUE), или только сам узел (FALSE). Значением по умолчанию является FALSE.

DELETE-NODE() - открепляет узел от структуры XML и удаляет его из памяти.

GET-ATTRIBUTE(name) - возвращает значение указанного атрибута элемента.

  • name  - имя атрибута, тип CHARACTER.

GET-ATTRIBUTE-NODE(attr-node-handle, name) - возвращает handle указанного атрибута элемента.

  • attr-node-handle - handle возвращаемого атрибута;
  • name - имя возвращаемого атрибута, тип CHARACTER.

GET-PARENT(x-node-handle) - возвращает handle родителя. Для корневого элемента XML возвращается неизвестное значение (?).

  • x-node-handle - handle возвращаемого родительского узла.

LONGCHAR-TO-NODE-VALUE(longchar) - метод присвоения значения LONGCHAR типа атрибуту X-NODEREF:NODE-VALUE.

  • longchar - присваиваемое значение LOGNCHAR типа.

MEMPTR-TO-NODE-VALUE(memptr) - метод присвоения значения MEMPTR типа атрибуту X-NODEREF:NODE-VALUE.

  • memptr - присваиваемое значение MEMPTR типа.

NODE-VALUE-TO-LONGCHAR(longchar [codepage]) - метод вывода значения X-NODEREF:NODE-VALUE с преобразованием значения в LONGCHAR тип в указываемой текстовой кодировке.

  • longchar - приемник значения, тип LONGCHAR;
  • codepage - текстовая кодировка, тип CHARCTER.

NODE-VALUE-TO-MEMPTR(memptr) - метод вывода значения X-NODEREF:NODE-VALUE с преобразованием значения в тип MEMPTR.

  • memptr - приемник значения, тип MEMPTR.

REMOVE-ATTRIBUTE({attribute-name | index} [, namespaceURI]) - удаляет атрибут элемента. Если удаляемому атрибуту определено начальное значение в описании DTD, то он устанавливается для атрибута.

  • attribute-name - имя атрибута, тип CHARACTER;
  • index - порядковый номер атрибута в списке атрибутов элемента (нумерация начинается с 1), тип INTEGER;
  • namespaceURI - URI пространства имен элемента, тип CHARACTER.

SET-ATTRIBUTE(name, value) - добавляет атрибут элементу. Если атрибут с таким именем уже существует у элемента, то его значение заменятся значением добавляемого атрибута.

  • name - имя добавляемого атрибута, тип CHARACTER;
  • value - значение атрибута, тип CHARACTER.

 

СОЗДАНИЕ XML-ДОКУМЕНТА


DEF VAR hDoc      AS HANDLE  NO-UNDO.
DEF VAR hRoot     AS HANDLE  NO-UNDO.
DEF VAR hPerson   AS HANDLE  NO-UNDO.
DEF VAR hAccounts AS HANDLE  NO-UNDO.
DEF VAR hField    AS HANDLE  NO-UNDO.
DEF VAR hText     AS HANDLE  NO-UNDO.

CREATE X-DOCUMENT hDoc.
CREATE X-NODEREF  hRoot.
CREATE X-NODEREF  hPerson.
CREATE X-NODEREF  hAccounts.
CREATE X-NODEREF  hField.
CREATE X-NODEREF  hText.

/* Определяем свойства XML-документа */
hDoc:ENCODING  = "windows-1251".

/* Создаем корень XML и помещаем его в дерево */
hDoc:CREATE-NODE(hRoot,"persons","ELEMENT").
hDoc:APPEND-CHILD(hRoot).

FOR EACH person WHERE person.person-id < 3
                NO-LOCK:
   /* Создаем ветку person и помещаем ее в корень XML */

   hDoc:CREATE-NODE(hPerson,"person","ELEMENT").
   hRoot:APPEND-CHILD(hPerson).

   /* Содаем атрибуты ветки person */
   hPerson:SET-ATTRIBUTE("LastName",  person.name-last).
   hPerson:SET-ATTRIBUTE("FirstName", person.first-name).

   /* Создаем ветку accounts и помещаем ее в person */  
   hDoc:CREATE-NODE(hAccounts,"accounts","ELEMENT").
   hPerson:APPEND-CHILD(hAccounts).

   FOR EACH acct WHERE acct.cust-cat EQ "Ч"
                   AND acct.cust-id  EQ person.person-id
                 NO-LOCK:
      /* Создаем тег account и помещаем его в ветку Accounts  */
      hDoc:CREATE-NODE(hField, "account", "ELEMENT").
      hAccounts:APPEND-CHILD(hField).

      /* Создаем значение тега account и помещаем его в тег */
      hDoc:CREATE-NODE(hText, "", "TEXT").
      hText:NODE-VALUE = acct.acct.
      hField:APPEND-CHILD(hText).

      /* Создаем атрибут тега account */
      hField:SET-ATTRIBUTE("currency", acct.currency).
   END.
END.    
 
/* выгружаем XML файл */
hDoc:SAVE("file","person.xml").

DELETE OBJECT hDoc.
DELETE OBJECT hRoot.
DELETE OBJECT hPerson.
DELETE OBJECT hAccounts.
DELETE OBJECT hField.
DELETE OBJECT hText

В результате мы получим примерно следующий XML файл.

<?xml version="1.0" encoding="windows-1251" ?>
<persons>
   <person FirstName="Иван Иванович" LastName="Иванов">
      <accounts/>
   </person>
   <person FirstName="Петр Петрович" LastName="Петров">
      <accounts>
         <account currency="">40817810000000000001</account>
      </accounts>
   </person>
   <person FirstName="Сидор Сидовович" LastName="Сидоров">
      <accounts>
         <account currency="">40817810000000000002</account>
         <account currency="840">40817840000000000001</account>
      </accounts>
   </person>
</persons>   


ЧТЕНИЕ XML-ДОКУМЕНТА


Для примера, прочитаем созданный нами person.xml

DEF VAR hDoc      AS HANDLE  NO-UNDO.
DEF VAR hRoot     AS HANDLE  NO-UNDO.
DEF VAR vName     AS CHAR    NO-UNDO.

DEF TEMP-TABLE tt-acct NO-UNDO
   FIELD name     AS CHAR FORMAT "x(40)"
   FIELD acct     AS CHAR FORMAT "x(20)"
   FIELD currency AS CHAR
.

CREATE X-DOCUMENT hDoc.
CREATE X-NODEREF  hRoot.

hDoc:LOAD("FILE","person.xml",FALSE).
hDoc:GET-DOCUMENT-ELEMENT(hRoot).

RUN getChildren(hRoot, 1).

DELETE OBJECT hDoc.
DELETE OBJECT hRoot.

PROCEDURE getChildren:   
   DEF INPUT PARAMETER hParent AS HANDLE NO-UNDO.
   DEF INPUT PARAMETER iLevel AS INTEGER NO-UNDO.
   DEF VAR hNode     AS HANDLE  NO-UNDO.
   DEF VAR hText     AS HANDLE  NO-UNDO.
   DEF VAR ix        AS INT     NO-UNDO.
   CREATE X-NODEREF  hNode.
   CREATE X-NODEREF  hText.

   REPEAT ix = 1 TO hParent:NUM-CHILDREN:
      hParent:GET-CHILD(hNode, ix).
      IF hNode:SUBTYPE <> "element" THEN NEXT.
      IF hNode:NAME = "person" THEN
         vName = hNode:GET-ATTRIBUTE("LastName") + " " +
                 hNode:GET-ATTRIBUTE("FirstName").
      IF hNode:NAME = "account" THEN
      DO:
         hNode:GET-CHILD(hText, 1).
         CREATE tt-acct.
         ASSIGN
            tt-acct.name     = vName
            tt-acct.acct     = hText:NODE-VALUE
            tt-acct.currency = hNode:GET-ATTRIBUTE("currency")
         .
      END.
      RUN getChildren(hNode, iLevel + 1).
   END.
   DELETE OBJECT hNode.
   DELETE OBJECT hText.
END PROCEDURE.

FOR EACH tt-acct.
   DISPL tt-acct.
END.

Результатом процедуры будет:

┌──────────────────────────────────────────────────────────────────────┐
│name                                     acct                 currency│
│──────────────────────────────────────── ──────────────────── ────────│
│Петров Петр Петрович                     40817810000000000001         │
│Сидоров Сидор Сидовович                  40817810000000000002         │
│Сидоров Сидор Сидовович                  40817840000000000001 840     │
│                                                                      │
└──────────────────────────────────────────────────────────────────────┘

Вы здесь: Главная Основы ABL РАБОТА C ОБЪЕКТНОЙ МОДЕЛЬЮ XML-ДОКУМЕНТА (DOM)