Глава 8.2. Определение типа документа8.2.1. Общие сведенияВ предыдущей главе мы неоднократно подчеркивали, что интерес к XML обусловлен, в первую очередь, возможностью создания на его основе специализированных языков, имеющих собственные наборы тегов. Однако, описанная там структура XML-документа и разбор его XML-процессором позволяют произвести только простую проверку того, что документ является правильно оформленным. Для создания на этой основе специализированных языков необходимы дополнительные средства описания этих языков. XML поддерживает два механизма подобных описаний: определения типа документа (document type definition, DTD) и XML-схемы (XML schema). Схемы будут описаны в гл. 8.6, здесь же мы приводим подробное описание правил создания DTD. Синтаксис DTD соответствует правилам языка SGML, поэтому DTD в XML по сути своей те же, что DTD в HTML. Однако, описывая HTML, мы ограничились простой констатацией их существования, поскольку для практической работы с HTML-документами формальное описание DTD не нужно. Совершенно по-другому обстоят дела в XML. Здесь DTD служит той основой, на которой базируется синтаксический анализ XML-документа. Именно DTD позволяет XML-процессору проверить не только, правильно ли оформлен документ, но и соответствует ли он описанию конкретного языка. По отношению к DTD все XML-процессоры делятся на верифицирующие (validating) и неверифицирующие (non-validating). Неверифицирующий процессор проверяет документ только на правильность оформления; верифицирующий, кроме того, проверяет его на соответствие заданной в декларации типа документа DTD. Документ, прошедший такую проверку, называется правильным (valid). DTD представляет собой набор деклараций, которые могут быть
Эти декларации могут содержаться (все или частично) в параметрических разделах. 8.2.2. Декларации типов элементовСинтаксис: <!ELEMENT имя спецификация> Декларация типа элемента определяет, какое содержимое может иметь элемент с данным именем. Возможное содержимое элемента задается спецификацией, которая может быть:
Список детей это заключенный в круглые скобки список имен элементов или ссылок на параметрические разделы, которые могут или должны содержаться в данном элементе. Список детей может также содержать подсписки, в свою очередь заключенные в круглые скобки. Элементы списков разделяются запятыми. Каждое имя элемента или подсписок может сопровождаться специальными символами:
Например, для элементов book и bookstore из предыдущей главы мы можем написать такие декларации типов: <!ELEMENT book (title, author+, price, present?)> <!ELEMENT bookstore (book*)> Здесь указано, что элемент book состоит из одного элемента title, одного или нескольких элементов author, элемента price и необязательного элемента present, а элемент bookstore состоит из любого количества элементов book. Элемент author имеет более сложное строение: он может состоять либо из двух элементов first-name и last-name, либо из единственного элемента name. Подобные варианты включаются в списки элементов с помощью разделителя вертикальная черта (|), например, в данном случае: <!ELEMENT author ((first-name, last-name) | name)> Смешанный описатель используется в тех случаях, когда элемент помимо других элементов может иметь текстовое содержимое. Если он имеет только символьное содержимое, как title в нашем примере, то его декларация имеет вид: <!ELEMENT title (#PCDATA)> Ключевое слово #PCDATA происходит от словосочетания "parsed character data", т. е. произвольные символьные данные, понимаемые XML-процессором. В некоторых случаях элемент может иметь символьное содержимое вперемешку с элементами. Например, описывая упрощенный диалект языка HTML, мы могли бы определить элемент P (абзац), как текст, фрагменты которого могут быть выделены курсивным или полужирным шрифтом (элементы I и B соответственно). Тогда его декларация имела бы следующий вид: <!ELEMENT P (#PCDATA|B|I)*> Подобный список должен начинаться с #PCDATA и иметь после себя звездочку: это означает, что элементы списка могут повторяться внутри определяемого элемента многократно. Примеры использования ссылок на параметрические разделы в списках элементов приведены ниже. 8.2.3. Декларации списков атрибутовСинтаксис: <!ATTLIST имя спецификация_атрибута*> спецификация_атрибута: имя тип параметры Декларация списка атрибутов позволяет задать список допустимых атрибутов для элемента с данным именем. Для каждого атрибута мы должны указать его имя, тип и дополнительные параметры). 8.2.3.1. Типы атрибутовАтрибуты в XML бывают трех типов: строковые, именные (tokenized) и списочные.
8.2.3.2. Дополнительные параметры атрибутовПараметры атрибутов могут принимать следующие значения:
8.2.3.3. Примеры описания атрибутовВ качестве примера рассмотрим список атрибутов элемента button в языке XHTML. <!ATTLIST button id ID #IMPLIED class CDATA #IMPLIED style CDATA #IMPLIED title CDATA #IMPLIED lang NMTOKEN #IMPLIED xml:lang NMTOKEN #IMPLIED dir (ltr|rtl) #IMPLIED name CDATA #IMPLIED value CDATA #IMPLIED type (button|submit|reset) "submit" disabled (disabled) #IMPLIED tabindex CDATA #IMPLIED accesskey CDATA #IMPLIED > В этом списке атрибут id является уникальным идентификатором элемента, lang и xml:lang задаются кодом языка, dir может принимать значения ltr или rtl, а type значения button, submit и reset, причем его значением по умолчанию является submit. Все остальные атрибуты являются строковыми и не имеют значений по умолчанию. В нашем примере с книжным магазином элемент book имеет один обязательный атрибут genre. Поэтому его декларация атрибутов будет иметь вид: <!ATTLIST book genre CDATA #REQUIRED> 8.2.4. Декларации нотацийНотации это имена, идентифицирующие формат неанализируемых разделов, формат элементов, имеющих атрибут нотации, или прикладную программу, которой адресована директива. Декларация нотации имеет две формы: <!NOTATION имя SYSTEM URI> <!NOTATION имя PUBLIC строка URI?> В первом варианте имя нотации связывается с внешним ресурсом, заданным своим URI, во втором с публичным идентификатором нотации и, возможно, с внешним ресурсом. Как внешний, так и публичный идентификаторы могут использоваться XML-процессором для вызова соответствующей прикладной программы, обрабатывающей разделы данного формата. Для каждого имени нотации допустима только одна его декларация. Пример использования нотации: <!NOTATION gif SYSTEM "gifview.exe"> ... <!ENTITY photo SYSTEM "photo.gif" NDATA gif> В этом примере указано, что для обработки разделов в формате gif следует вызывать программу отображения GIF-образов gifview.exe. 8.2.5. Пример DTDТеперь мы можем оформить в виде законченной DTD правила описания нашей книжной базы данных. С учетом всего сказанного выше она будет иметь вид: <!DOCTYPE bookstore [ <!ELEMENT first-name (#PCDATA)> <!ELEMENT last-name (#PCDATA)> <!ELEMENT name (#PCDATA)> <!ELEMENT title (#PCDATA)> <!ELEMENT price (#PCDATA)> <!ELEMENT present EMPTY> <!ELEMENT author ((first-name, last-name) | name)> <!ELEMENT book (title, author+, price, present?)> <!ATTLIST book genre CDATA #REQUIRED> <!ELEMENT bookstore (book*)> <!ENTITY po "поэзия"> <!ENTITY pr "проза"> <!ENTITY dr "драматургия"> ]> 8.2.6. Параметрические разделыПараметрические разделы (parameter entities) это макроопределения, обеспечивающие более сложные текстовые подстановки, чем обычные анализируемые разделы. Параметризованный раздел декларируется следующим образом: <!ENTITY % имя значение> Таким образом, отличие его декларации от обычного раздела состоит только в наличии символа
процента (%) перед именем раздела. Для ссылок на параметрические разделы используется
конструкция <!ENTITY % bookstore SYSTEM "bookstore.dtd"> %bookstore; Для уменьшения объема DTD мы могли бы создать параметрический раздел text вида <!ENTITY % text "(#PCDATA)"> и затем изменить приведенные выше декларации так: <!ELEMENT first-name %text;> <!ELEMENT last-name %text;> 8.2.7. Условные секцииXML позволяет включать во внешнюю DTD т. н. условные секции (conditional sections), которые либо обрабатываются, либо игнорируются XML-процесором. Эта возможность особенно полезна при отладке DTD, т. к. позволяет нам включать и выключать отдельные фрагменты DTD, не изменяя ее содержания. Условных секций две: <![IGNORE[ декларации ]]> <![INCLUDE[ декларации ]]> Первая из них указывает XML-процессору, что ее содержимое должно им игнорироваться, а вторая что ее содержимое должно обрабатываться обычным образом. Содержимым этих секций могут быть любые синтаксически законченные декларации, допустимые в DTD. Поясним использование условных секций на примере. Допустим, что в процессе отладки bookstore.dtd мы решили создать два варианта этой DTD: отладочный (draft) и окончательный (final). Тогда для отладки мы можем написать следующее: <!ENTITY % draft 'INCLUDE'> <!ENTITY % final 'IGNORE'> <![%draft;[ <!ELEMENT book (comments*, title, author+, price, present?)> ]]> <![%final;[ <!ELEMENT book (title, author+, price, present?)> ]]> Теперь процессор будет включать в DTD первую из приведенных деклараций элемента book и игнорировать вторую. После завершения отладки нам достаточно изменить только декларации разделов draft и final: <!ENTITY % draft 'IGNORE'> <!ENTITY % final 'INCLUDE'> |