Допустимые документы XML
DTD
В предыдущей статье мы рассказали, как создать правильно
оформленный документ XML.
Теперь давайте представим, что мы работаем в некоторой компании. В отделе
разработки это компании работают несколько разработчиков, и все используют в
своих работах документы XML.
Соответственно, можно предположить, что каждый разработчик составляет
собственный документ со своей структурой. А теперь предположим, что для
продуктов данной компании должна быть единая структура, единый механизм,
позволяющий потенциальному разработчику передать синтаксические правила словаря
другому пользователю языка XML.
Спецификация XML
1.0 позволяет использовать для создания допустимых (valid) документов XML стандарт
определения типа документа (Document Type Definition,
DTD). Кроме того,
существуют так называемые схемы XML,
которые могут передать не только структуру документа (т.е. в какой
последовательности или иерархии один элемент, либо узел, идет за другим), но и
каким каждый элемент (либо узел, атрибут и т.д.) должен быть (тип, ограничения
на размер и т.п.).
В силу ограниченности объема статьи, мы не сможем в полной
мере освятить все стороны применения той или иной технологии (существуют даже
целые книги, посвященные исключительно схемам XML, а одна из рекомендаций такой схемы
составляет несколько страниц формата А4).
В первой части статьи мы постараемся кратко рассказать об
основных принципах создания определений типа документа, далее мы рассмотрим
несколько видов схем XML.
Document
Type Definition (DTD)
Для начала напишем небольшой документ XML, на основе которого будем составлять
определения DTD и схемы XML.
На рисунке 1 (рис. 1) показана структура рассматриваемого документа.
<?xml version="1.0"
encoding="Windows-1251"?>
<!DOCTYPE books SYSTEM
"books.dtd">
<books>
<book id="1">
<title>Основы
создания документов XML</title>
<author>Иванов</author>
<pubdate>12.03.2002</pubdate>
<price cash="USD">10</price>
</book>
<book id="2">
<title>Защита COM/DCOM</title>
<author>Петров</author>
<pubdate>21.01.2002</pubdate>
<price cash="USD">15</price>
</book>
</books>
|
Рис. 1
|
Прежде чем приступать к написанию будущего определения DTD, давайте разберем тэг DOCTYPE в
имеющемся документе XML:
<!DOCTYPE books SYSTEM … >. Данный тэг «говорит» нам, что документ
соответствует синтаксису XML
1.0 и использует словарь books – тип “books”.
За этим объявлением следует ключевое слово. Оно может принимать два значения: SYSTEM или
PUBLIC. SYSTEM говорит
анализатору искать файл определений DTD по адресу URL, следующему за ключевым словом. PUBLIC же
интерпретируется немного сложнее. Ключевое слово PUBLIC «говорит» анализатору, что данное
определение DTD предназначено для хорошо известных словарей (ярким примером
тому является определение словаря HTML: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">). При этом адрес
соответствующего определения DTD определяется по идентификатору URI (Uniform Resource Identifier –
Универсальный Идентификатор Ресурса), который может принимать значения URL или
просто уникального имени.
Также стоит сказать, что определения DTD могут быть
не только внешними как в нашем примере, но и внутренними. Тогда в объявлении XML документа
атрибут standalone
может принимать значение “yes”. Стоит добавить, что на
практике данный атрибут не используется. В принципе, наличие атрибута standalone со
значением “no” не
гарантирует наличие внутренних определений.
Теперь перейдем к разбору определений на примере определения
вышепредставленного документа XML.
Файл определений DTD представлен
ниже на рисунке 2 (рис. 2).
<?xml
version="1.0" encoding="Windows-1251"?>
<!ELEMENT books (book+)>
<!ELEMENT book (title, author,
pubdate, price)>
<!ATTLIST book id CDATA #REQUIRED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT pubdate (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST price cash CDATA
#REQUIRED>
|
Рис. 2
|
Для начала приведу таблицу основных элементов определений DTD (рис. 3).
Определение DTD
|
Расшифровка
|
<!ENTITY
… >
|
Декларирует общую сущность
и позволяет объявить фрагмент анализируемого текста, связанный с
именем, по которому на этот текст будет производится ссылка.
<!ENTITY copyright “Super Company, 2000”> - объявляет ссылку
на сущность авторского права
|
<!ELEMENT
имя
тип >
|
Объявляет ссылку на элемент исходного документа XML. Значение поля «имя» равно имени
элемента в документе XML,
а поле «тип» объявляет
тип элемента, который может принимать значения: EMTY – пустой
элемент; ANY – любое содержание. <!ELEMENT title (#PCDATA)> - говорит, что в документе XML должен
быть элемент title,
чье содержание может быть любым.
|
<!ATTLIST имя атрибут тип параметр >
|
Объявляет ссылку на атрибут элемента документа XML. Параметр «имя» должен быть равен имени элемента, на атрибут
которого указывает данный тэг. Поле «атрибут»
указывает на имя атрибута элемента. «Тип»
«говорит», какой тип имеет данный атрибут. Тип атрибута может принимать
следующие значения:
CDATA
|
Символьные данные (строка)
|
ID
|
Имя, уникальное для данного документа
|
IDREF
|
Ссылка на некоторый элемент с атрибутом ID, который
имеет то же значение, что и атрибут IDREF
|
IDREFS
|
Несколько атрибутов IDREF
|
ENTITY
|
Имя заранее определенной внешней сущности
|
ENTITIES
|
Несколько заранее определенных внешних сущностей, разделенных
пробелами
|
NMTOKEN
|
Имя
|
NMTOKENS
|
Несколько имен NMTOKEN, разделенных пробелами
|
NOTATION
|
Принимает одно из имен, указывающих на типы нотаций в определении
DTD
|
[Список значений]
|
Принимает одно из серии значений, явным образом
определенных пользователем, которые может атрибут
|
«Параметр» указывает на
значение по умолчанию для атрибута. «Параметр»
может принимать значения: #REQUIRED – атрибут должен
присутствовать в каждом экземпляре документа; #IMPLIED –
атрибут может присутствовать в экземпляре документа, но не обязательно; #FIXED + значение – атрибут должен всегда иметь только то
значение, которое предлагается по умолчанию; «только значении по умолчанию» -
если атрибут не указан, значение по умолчанию предполагается анализатором.
Если атрибут имеется, у него может быть другое значение.
<!ATTLIST price cash CDATA #REQUIRED> - декларирует атрибут
cash элемента price, имеющий строковый тип с обязательным присутствием в
каждом элементе price.
|
<!NOTATION тип параметр имя>
|
Представляет собой декларацию форматирования для внешнего
содержания, которое не должно быть проанализировано, а также для внешних
приложений, обрабатывающих это содержание. Тип указывает
на само внешнее содержание; параметр принимает
значения SYSTEM или PUBLIC (о них мы уже говорили); имя указывает имя, либо путь на
внешний обработчик содержания: <!NOTATION jpeg SYSTEM “jpgviewer.exe”>
|
Рис. 3
|
Мы познакомились с
основными тэгами определений DTD,
теперь же давайте рассмотрим, как строятся эти определения на примере нашего
документа XML.
Первая строка файла определений DTD соответствует
декларации документа XML.
Любые документы XML начинаются с этой декларации, будь-то сам документ XML, определение DTD, схема XML и т.п.
Далее мы объявляем элемент books,
указывая, что данный элемент содержит один и более элементов book:
<!ELEMENT books (book+)> .
Кстати объявления один и более, ноль и более или
необязательный оператор задаются следующим образом:
один и более – после имени ставиться знак плюса (+); ноль и
более – ставиться после имени знак звездочки (*); необязательный оператор,
который может присутствовать или не присутствовать декларируется вопросительным
знаком (?).
Вернемся к документу. После декларации элемента books, мы
переходим к объявлению элемента book.
<!ELEMENT
book (title, author, pubdate, price)> . Здесь объявление DTD говорит
анализатору, что существует такой элемент book, который содержит в себе в строго
последовательности элементы title, author, pubdate, price. Опять же вернемся к лирическому отступлению и поговорим о
том, как объявить строгую последовательность или какую-нибудь другую. Здесь все
просто – запятая ( , ) определяет строгую последовательность, т.е. анализатор
понимает, что элементы, перечисленные через запятую должны следовать именно
так, как они определены в DTD.
Знак вертикальной черты ( | ) определяет выбор. К примеру, рассмотрим следующее
объявление:
<!ELMENT
a (b, (c | d) | e)> .
Что мы видим? Есть элемент a, который содержит в себе элементы b, c, d, e. Эти элементы
следуют друг за другом в особой последовательности. Сначала обязательно должен
идти элемент b,
далее мы видим следующую структуру: (c | d) | e . Давайте ее разберем. Путь наших мыслей начнем с
внешних границ, постепенно углубляясь внутрь. Здесь мы видим следующее: определение DTD говорит
анализатору, что за элементом b может идти либо то,
что находится в скобках, либо элемент e. Кроме того, в скобках мы тоже видим не
строгую последовательность – может идти элемент c или d. В итоге мы
имеем. После элемента a должен идти элемент b, далее могут
идти элементы c или d, либо e. Однако все
элементы должны присутствовать. Если бы мы написали вот такое определение вроде
<!ELEMENT a (b+,
(c | d*) | e?)>,
то оно бы интерпретировалось следующим образом: за элементом a должен идти один или более элементов b, после может быть либо один элемент c, либо ноль и
более элементов d, либо элемент e, либо вообще ничего может и не быть. Кстати,
выбор предполагает, что если выбран одни из элементов, то другой уже не может
быть. Одновременно элементы c, d, e существовать не
могут, должен быть кто-то один.
После этого довольно долгого лирического отступления
вернемся к нашему определению DTD.
За объявлением элемента book следует
декларация атрибута данного элемента:
<!ATTLIST
book id CDATA #REQUIRED>. Данное определение говорит нам, что элемент book содержит в себе атрибут id, который
соответствует типу CDATA
(т.е. атрибут id может содержать в себе любой текст) и
имеет значение по умолчанию #REQUIRED (т.е. атрибут id является обязательным и должен
присутствовать в каждом элементе book). После объявления атрибута следуют объявления элементов title, author, pubdate, price. Объявления данных элементов однотипны, так что остановимся
на разборе одного элемента price.
<!ELEMENT price (#PCDATA)>. Эта декларация элемента говорит анализатору, что есть
элемент price,
который содержит в себе любое текстовое значение (под текстовым значением
подразумевается, что текстом может быть любая строка, будь-то текст или числа).
После объявления элемента price идет декларация
атрибута данного элемента. <!ATTLIST price cash CDATA #REQUIRED>. Здесь утверждается, что элемент price содержит атрибут cash, который является
обязательным во всех экземплярах элемента и содержит в себе любое текстовое
значение.
Кстати, последовательность, в которой объявлены все элементы и атрибуты можно изменить как вам
заблагорассудится, т.е. совсем не обязательно сначала объявлять элемент books, затем элемент book после атрибут id. Декларации элементов и атрибутов можно ставить в
любой последовательности и не обязательно, чтобы за декларацией элемента шла
декларация его атрибута. Можно в начале документа объявить элемент, а в конце
документа – его атрибут. Анализатор все равно поймет все так, как написано в
объявлениях.
Итак, подведем некоторые итоги. Мы рассмотрели некоторый
документ XML и написали к нему DTD-определение. Если вы внимательно изучили это DTD-определение, то заметили
его недостатки. Взгляните на атрибуты элементов book и price. Как было сказано, они
могут принимать любые текстовые значения, а нам нужно, чтобы атрибут
id мог принимать только целочисленные значения,
а атрибут cash – значения идентификатора валюты. Объявление
атрибута cash можно изменить (измененный фрагмент помечен
красным): <!ATTLIST price cash (USD | EUR | RUB) #REQUIRED>. Что мы сделали? Мы
изменили тип атрибута с текстового на перечисляемый.
Теперь атрибут cash может принимать только значения в скобках
и никакие другие. Теперь давайте перейдем к атрибуту id. Конечно, ему тоже можно
дать перечисляемый тип. Написав в скобках что-то вроде этого: (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10). Это хорошо,
но, во-первых, мы не знаем сколько у нас книг
(может их миллион), во-вторых, мы не застрахованы от появления нескольких
одинаковых значений атрибута id.
Теперь уже видно, что для такой строгой структуры как XML нужна не менее
строгая типизация. Данное свойство нам могут предоставить схемы XML, о которых будет рассказано
в следующей части статьи.