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 данный документ представляется следующим деревом объектов:
Каждый узел имеет своего единственного "родителя" (узел, располагающийся непосредственно над ним). Родительские узлы, в свою очередь, обладают так называемыми дочерними узлами (узлами, расположенными непосредственно под ними). У одного "родителя" может быть несколько дочерних узлов, при этом, каждый из них имеет свой порядковый номер начиная с 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-node - handle импортируемого X-NODREF объекта;
- deep - значение LOGICAL типа, определяющее осуществлять импорт всего поддерева элемента (TRUE) или импортировать только непосредственно сам элемент (FALSE). Значением по умолчанию является FALSE.
INSERT-BEFORE(x-ref-handle1, x-ref-handle2) - осуществляет добавление узла в структуру XML как дочернего по отношению к тому узлу, чей метод вызывается и размещаемого после указываемого другого дочернего узла этого же родителя. Если узел, за которым должен быть размещен добавляемый элемент не указан, то он будет последним дочерним узлом.
- x-ref-handle1 - handle объекта 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 | чтение | Тип узла. Возможны следующие значения:
|
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 │
│ │
└──────────────────────────────────────────────────────────────────────┘