Введение в язык определения типов Document Type Definition (DTD) |
В спецификация XML 1.0 указывается, что логическую структуру XML-документа (подробности об XML см. в Кратком введении в XML) можно описать с помощью языка Определений Типов Документов - Document Type Definition (DTD) http://www.w3.org/TR/REC-xml#dt-doctype. В DTD используется формальная грамматика, позволяющая определить как структуру документа, так и допустимые значения. При обработке документов, если с ними будут ассоциированы правила, оформленные на языке DTD, анализаторы могут проверять данные на их соответствие с описаниями, тем самым сигнализировать о наличие структурных ошибок в данных XML-документов.
Зачем это нужно? Для упрощения программ обработки XML-документов. Так программа обработки может быть упрощена за счёт того, что она написана для работы с конкретной структурой документа, и не способной работать с множеством других различных структур. В то время как формальная проверка экземпляра конкретного документа на соответствие наперёд заданной структуре, предотвратит попаданию ошибочных данных на обработку такой программе.
Правильно оформленные документы (см. Правильно оформленные документы во Введении в XML), написанные в соответствии с неявными правилами для языка XML не способны выполнить подобный контроль данных. Ошибки в данных могут быть пропущены и тогда они приведут либо к не способности приложения выполнить работу с документом, либо могут привести к получению некорректных результатов его работы. Напротив, при наличии описания структуры на DTD при обработке документа (см. Состоятельные (или допустимые) документы во Введении в XML), его данные могут быть подвергнуты анализаторами, обеспечивающими проверку документа на допустимость, контролю на соответствие данных грамматическим правилам, описанным в нём (см. XML-анализаторы во Введении в XML). Таким образом, если требуется эффективный контроль проверки структурных ошибок в документе, то можно воспользоваться определениями, написанными на DTD и анализатором, проверяющим документ на допустимость.
Конечно, для обработки всего одного временного документа, вы вряд ли будете разрабатывать словарь, однако при массовой обработке большого количества документов с одинаковой структуры, вам такой контроль описания этой самой структуры, скорее всего потребуется.
Определения, написанные на DTD могут быть связаны (ассоциированы) с XML-документами. Таким образом, анализаторы, проверяющие XML-документ на допустимость могут осуществить проверку корректности структуры документа по отношению к описаниям. DTD-описания могут быть внешними, внутренними или и теми и другими, т.е. смешанными. В последнем случае внутренние имеют более высокий приоритет над внешними (т.е. переопределяют последние). Связь между XML-документом и DTD-описанием осуществляется с помощью декларации DOCTYPE, помещаемой в XML-документ (см. Декларация типа документа во Введении в XML).
Декларация DOCTYPE представляет из себя тег следующей структуры:
<!DOCTYPE Name ExternalID MarkupDecl >
где
Допустимое в XML-содержание определяется следующими декларациями в DTD:
Конструкция в DTD | Назначение |
ELEMENT | - декларации типа элемента XML |
ATTLIST | - декларации атрибутов, могут быть назначены конкретным элементам, а также определить разрешённые значения атрибутов |
ENTITY | - декларации повторно используемого содержания |
NOTATION | - декларации определяют внешнее содержание |
Элемент является основным объектом языка XML, в DTD элемент объявляется с помощью тега ELEMENT и имеет следующую структуру:
<!ELEMENT Name contentspec>
где
Name - имя типа элемента. На имя типа элемента накладываются следующие ограничения, всегда применяемые к именам в XML (см. также Имена во Введении в XML): имена могут содержать буквы, цифры, двоеточия (':'), символ нижнего подчёркивания ('_'), дефис (тире или знак минуса) ('-') и точку ('.'), но не могут начинаться с цифры. Они должны начинаться только с буквы, знака подчёркивания или двоеточия.
contentspec - определяет содержание элемента и может быть:
В последнем случае различают две модели содержания:
Формальные правила, с помощью которых определяют содержание элемента, очень похожи на те, которые используются в расширенных формах Бэкуса-Наура (Extended Backus-Naur Form - EBNF) при определении синтаксиса в языках программирования.
В таблице ниже представлены символы-разделители между элементами:
Символ | Назначение |
, | - определяет последовательность |
| | - указывает на выбор одного из |
При помощи первого (символ запятая ','), элементы можно объединить в последовательность, создав список элементов. Например:
<!ELEMENT PersonName (First, Middle, Last)>
<!ELEMENT FruitBasket (Apple | Orange)>
Повторяемость элемента или группы элементов (определитель множественности или кардинальность), задаётся следующими символами:
Символ | Назначение |
? | - не обязательный, может отсутствовать |
* | - ноли или больше |
+ | - один или больше |
Отсутствие символа повторяемости указывает, что элемент должен присутствовать, причём только один раз. Символ повторяемость ставится сразу за названием элемента или сразу за закрывающей круглой скобкой группы элементов. Вот пример с использованием символов повторяемости:
<!ELEMENT FruitBasket (Cherry+, (Apple | Orange)*)>
и эта группа модели содержания означает, что наша корзина может содержать один или несколько элементов Cherry, после которых следует ноль или больше экземпляров выбора между элементами Apple и Orange. Обратите внимание, что элементы Cherry должны быть расположены вместе. Ниже пример данных, удовлетворяющий такой декларации:
<FruitBasket> <Cherry>...</Cherry> <Cherry>...</Cherry> <Apple>...</Apple> <Orange>...</Orange> <Orange>...</Orange> </FruitBasket>
Вот ещё несколько примеров определений элементов:
<!ELEMENT foo (A?, ((B, C) | D), E?)>
здесь определено, что элемент foo может содержать от одного до четырёх порождённых элементов, в зависимости от сделанного выбора, причём первым может быть A, B или D (элемент A не обязателен), затем появляется B и C, или D, в завершении E (элемент E не обязателен).
<!ELEMENT foo (A, (B, C)*, D+)>
здесь за элементом A следует ноль или больше пар B и C, а в конце по крайней мере один элемент D.
Для того, чтобы указать на смешанное содержание, в модель содержания введено ключевое слово #PCDATA. В этом случае элементы модели содержания следует разделять символом | и у группы в целом объявить множественность "ноли или больше":
<!ELEMENT MixedBag (#PCDATA | ItemA | ItemB)*)>
Ниже пример данных, удовлетворяющий такому описанию:
<MixedBag> <ItemA>...</ItemA> Текст, включённый как PCDATA <ItemA>...</ItemA> <ItemB>...</ItemB> </MixedBag>
Нужно также иметь ввиду, что один и тот же элемент не может быть объявлен более чем один раз.
Атрибуты, подобны свойствам в ООП у классов, и информационно дополняют XML-элементы (см. также раздел Атрибут во Введении в XML). Объявления атрибутов DTD имеют следующую структуру:
<!ATTLIST ElementName AttDef* >где ElementName - имя элемента, для которого объявляются атрибуты, а AttDef имеет следующую структуру:
AttDef ::= AttName AttType DefaultDecl
здесь AttName - имя атрибута, AttType - тип атрибута, а DefaultDecl - значение атрибута. На имя атрибута наложены такие же ограничения, что и имя XML-элемента (см. в разделе ELEMENT данного документа, а также раздел Имена во Введении в XML).
Тип атрибута (AttType) может быть одним из следующих:
Тип | Назначение |
CDATA | - символьные данные |
ID | - уникальный идентификатор |
IDREF | - ссылка на уникальный идентификатор |
IDREFS | - набор ссылок на уникальные идентификаторы |
ENTITY | - сущность (или замещаемое содержание) |
ENTITIES | - набор сущностей |
NMTOKEN | - именной токен |
NMTOKENS | - набор именных токенов |
NOTATION | - один из типов нотаций |
[явное перечисление] | - перечисление возможных значений атрибутов |
Следует сделать несколько пояснений к типам атрибутов:
DefaultDecl - определяет: как и какие значения должны быть присвоены атрибуту. В качестве значений могут быть:
Значение | Назначение |
#REQUIRED | - атрибут должен всегда присутствовать в каждом элементе и иметь значение |
#IMPLIED | - атрибут является не обязательным и может отсутствовать в элементе |
#FIXED + значение | - определяет атрибут, всегда имеющий одно и тоже значение |
значение | - значение, заключённое в кавычки, определяет значение по умолчанию |
Нужно иметь ввиду, что если анализатор встречает объявленный, но отсутствующий атрибут, для которого определено значение по умолчанию, то в рекомендациях предписывается, что он должен вести себя так, как будто атрибут присутствует и имеет значение по умолчанию.
Например:
<!ATTLIST product title CDATA #REQUIRED id ID #IMPLIED type NMTOKEN #REQUIRED; quantity CDATA "1" value CDATA #FIXED "дорого" color (серый|белый) "серый" >
определяет для элемента product следующие атрибуты:
Атрибут | Требования к значению |
title | - обязательный атрибут, содержащий символьные данные |
id | - необязательный атрибут, который может содержать уникальный идентификатор элемента внутри документа |
type | - обязательный атрибут, значение которого произвольно, но обязано удовлетворять правилам имён в XML для типа NMTOKEN (например type="сыпучий") |
quantity | - определяет атрибут, который может и не присутствовать в элементе, в этом случае подразумевается, что его значение равно "1" |
value | - определяет атрибут, который всегда должен иметь значение "дорого" |
color | - определяет атрибут, имеющий одно из значений: "серый" или "белый", причём по умолчанию - "серый" |
Часто используемы конструкции языка или внешние данные, могут быть предварительно объявлены как сущности, а затем использованы в документе. Имеется два вида сущностей: внутренние и внешние.
Внутренняя сущность используется (в том числе и в значениях атрибутов) для повторного использования одних и тех же конструкций. Так, если одна и та же конструкция используется несколько раз, то можно объявить представляющую её сущность, а затем ссылаться на последнюю везде, где возникает необходимость в конструкции (см. также раздел Ссылки во Введении в XML). Близким аналогом таких сущностей являются макроподстановки в некоторых языках программирования. Например, объявление сущности animal:
<!ENTITY animal "слон" >
позволяет в дальнейшем её использовать (в том числе и в атрибутах) подобно:
<product title="&animal;" /> <!-- здесь после подстановки сущности значение атрибута title="слон" -->
Выше было показано объявление сущности, которая могла быть использована в любом месте XML-документа. Тем не менее, существует объявление сущностей, которые могут быть использованы только в рамках DTD-языка, например объявление элемента shape
<ELEMENT shape (x, y, z, R)>
после предварительного объявления сущности coords:
<!ENTITY % coords "x, y, z" >
может быть записано следующим образом:
<ELEMENT shape (%coords;, R)>
в то время как использование параметризованных сущностей в атрибутах аналогично показанному выше.
Объявление внешней сущности имеет
вид:
<!ENTITY имя ExternalID NDataDecl>
здесь:
ExternalID ::= 'SYSTEM' SystemLiteral | 'PUBLIC' PubidLiteral SystemLiteral
NDataDecl ::= 'NDATA' Name
где:
Следует также отметить, что:
Рассмотрим несколько примеров, поясняющих использование внешних сущностей.
<!ENTITY animal SYSTEM "ent/animal.ent" >
В данном случае определена внешняя разбираемая сущность (содержимое файла animal.ent с указанным относительным его расположением) и использование ссылки на сущность &animal; в любом месте XML документа будет приводить к замене ссылки сущности на содержимое указанного файла.
<!ENTITY animal PUBLIC "-//ZOO//Elephant/Description" "http://enimalhost.com/animal.ent" >
Это также определение внешней разбираемой сущности, однако теперь, специализированный анализатор для зоологических XML-файлов, встретив публичную и известную ему ссылку "-//ZOO//Elephant/Description", может и не загружать определение, находящееся по адресу http://enimalhost.com/animal.ent непосредственно с сервера. Как именно в данном случае определить сущность animal - ложится на плечи анализатора. Однако в любом случае, она (сущность animal) при использовании данного объявления должна быть корректно определена.
Оба примера выше определяли внешнюю разбираемую сущность, т.е. содержимое внешнего документа было обработано XML-анализатором, при этом подразумевается, что формат данных является текстовым и содержимое его совместимо с требованиями XML. Однако, известно что имеется целый ряд двоичных форматов (например изображения), и естественно возникает законный вопрос: а как работать с подобными данными средствами XML. Возможно ли вообще такое? Чтобы ответить на этот вопрос, следует познакомиться с нотациями.
XML-анализаторы не имеют средств по обработке двоичных файлов непосредственно. Что же делать, если мы в документе желаем использовать данные в формате двоичных файлов? Чтобы обойти эту проблему в XML используются объявления нотаций, которые позволяют связать названия форматов с внешними приложениями-обработчиками (helper application) для файлов этих форматов. Формально определение нотаций имеет вид:
<!NOTATION TypeName ExternalID>
здесь ExternalID по своей структуре полностью
аналогичен тому, что и во Внешней сущности у ENTITY,
т.е.:
ExternalID ::= 'SYSTEM' SystemLiteral | 'PUBLIC' PubidLiteral SystemLiteral
и определяет приложение-обработчик двоичных файлов для типа TypeName. Если в XML-документе использованы несколько различных форматов двоичных файлов (т.е. определёны как внешние сущности с применением NDATA у ENTITY), то при помощью этого определения необходимо указать соответствующие приложения-обработчики каждому из типов.
Применяя NOTATION, имеется две возможности обработки двоичных файлов в XML.
В первом вариант требуется:
Рассмотрим пример поясняющий это:
<!DOCTYPE menu [ <!ELEMENT menu (menuitem*)> <!ELEMENT menuitem EMPTY> <!ATTLIST menuitem image ENTITY #REQUIRED title CDATA #REQUIRED href CDATA #REQUIRED> <!NOTATION gif SYSTEM "gif-viewer.exe"> <!NOTATION jpg SYSTEM "jpg-viewer.exe"> <!ENTITY news SYSTEM "images/news.gif" NDATA gif> <!ENTITY products SYSTEM "images/products.jpg" NDATA jpg> <!ENTITY support SYSTEM "images/support.gif" NDATA gif> ]> <menu> <menuitem image="news" title="News" href="news.htm"/> <menuitem image="products" title="Products" href="products.htm"/> <menuitem image="support" title="Support" href="support.htm"/> </menu>
Здесь атрибут image у элемента menuitem, является обязательным, и принадлежит типу ENTITY. Это означает, что должны быть объявления используемых сущностей. Действительно, имеется три объявления внешних сущностей: news, products, и support, причём все три являются не анализируемыми, т.к. у каждой из них присутствует NDATA, определяющий соответствующий тип. При этом, задействовано всего два различных типа: gif и jpg, и каждому из них определёно приложение-обработчик, используя определения NOTATION, - это gif-viewer.exe и jpg-viewer.exe, соответственно.
Теперь рассмотрим второй вариант:
<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root type NOTATION (rtf|htm|txt) #REQUIRED> <!NOTATION rtf SYSTEM "wordpad.exe"> <!NOTATION htm SYSTEM "iexplore.exe"> <!NOTATION txt SYSTEM "notepad.exe"> ]> <root type="htm"> <![CDATA[ <html> <header> <title>Examp</title> </header> <body> <!-- Здесь содержимое документа --> </body> </html> ]]> </root>
Здесь через нотации определены три типа данных: rtf, htm, txt. Атрибут type элемента root указывает на формат данных, содержащихся в элементе. В данном случае это html-формат, обрабатываемый приложением iexplore.exe.
См. также: