Еще одним способом включения в содержимое XML-элементов недопустимых символов является использование т. н. секций CDATA (сокр. от Character DATA, т. е. символьные данные). Допустим, что мы хотим сделать содержимым элемента layout фрагмент HTML-текста, например:
<layout>
<H1>Заголовок</H1>
</layout>
Подобная конструкция неверна, т. к. HTML-тег H1 будет в данном случае воспринят как тег XML. Для того, чтобы все содержимое элемента layout воспринималось как данные, мы должны заключить его в секцию CDATA:
<layout>
<![CDATA[<H1>Заголовок</H1>]]>
</layout>
Cекция CDATA заключается в ограничители <![CDATA[ и ]]>. Все внутри этой секции считается символьными данными; в частности, секции CDATA не могут вкладываться друг в друга.
Физически XML-документ может состоять из несколько разделов (entities). При этом корневой элемент документа также является разделом, который называется разделом документа, хотя он никак специально не оформлен. Все разделы имеют содержимое; все они, кроме раздела документа и внешней DTD (Document Type Definition, описание типа документа), имеют имя.
С точки зрения синтаксического разбора документа разделы подразделяются на анализируемые и неанализируемые. Неанализируемый раздел (unparsed entity) — это ресурс, содержимое которого XML-процессор воспринимает как внешние данные без их синтаксического анализа (например, текст, не являющийся XML-документом). Неанализируемые разделы всегда имеют нотацию, указывающую на их формат. Анализируемые разделы (parsed entities) предназначены для текстовой подстановки: всякий раз, когда XML-процессор встречает в документе имя такого раздела, он заменяет его на содержимое этого раздела.
Декларации разделов подразделяются на внутренние и внешние. Декларация внутреннего раздела выглядит так:
<!ENTITY имя значение>
Она включает в себя содержимое объекта (параметр значение) и используется для подстановки этого значения вместо имени раздела. Мы можем, например, ввести в пример с книгами атрибут жанр и использовать для задания жанра внутренние разделы:
<!DOCTYPE spec [ <!ENTITY pr "проза"> <!ENTITY po "поэзия">]>
<books>
<book genre="&po;">
<title>Часть речи</title>
<author>Бродский, Иосиф</author>
</book>
<book genre="≺">
<title>Хрустальный горизонт</title>
<author>Месснер, Райнхольд</author>
</book>
</books>
Из этого примера видно, что ссылка на раздел (entity reference) выглядит точно так же, как ссылка на специальный символ, т. е. имеет вид &имя;. На самом деле, специальные символы — это точно такие же ссылки, но соответствующие разделы заданы неявно во внутренней декларации языка XML. Подобные текстовые подстановки удобны для задания сокращений, позволяющих уменьшить объем документа, и для введения обозначений для часто изменяемых полей документа. Так, например, мы можем вынести во внутренний раздел дату очередной ревизии публикации и затем изменять только значение этого раздела.
Существуют два варианта деклараций внешнего раздела:
<!ENTITY имя SYSTEM URI [NDATA нотация]?>
<!ENTITY имя PUBLIC строка? URI [NDATA нотация]?>
Первый вариант называется системным разделом, второй — публичным разделом. Они оба связывают имя раздела с внешним ресурсом, заданным своим URI, который должен иметь кодированную форму и не содержать закладок. URI внешнего ресурса называется системным идентификатором раздела. Использование внешнего ресурса зависит от нескольких факторов:
Если декларация содержит параметр NDATA, задающий нотацию раздела, то раздел является неанализируемым.
Если параметр NDATA не задан, то раздел анализируемый, и соответствующий ресурс должен быть XML-документом. Это означает, что вместо ссылки на раздел в текст документа будет включаться текст соответствующего ресурса.
Публичный раздел может содержать строку, задающую публичный идентификатор раздела. XML-процессор может использовать этот идентификатор для генерации альтернативного URI данного раздела. Если ему это не удалось, то он должен использовать системный идентификатор для загрузки содержимого раздела.
Примеры деклараций внешних ресурсов:
<!-- неанализируемый ресурс: GIF-образ -->
<!ENTITY photo SYSTEM "images/photo.gif" NDATA gif>
<!-- системный анализируемый ресурс -->
<!ENTITY hatch SYSTEM "http://www.textuality.com/boilerplate/hatch.xml">
<!-- публичный анализируемый ресурс -->
<!ENTITY hatch PUBLIC "-//Textuality//TEXT Standard hatch boilerplate//EN"
Внешний анализируемый раздел должен начинаться с директивы <?xml …?>, которая может не содержать номера версии, но обязана содержать кодировку символов. Эта директива не входит в состав подставляемого текста.
Декларация типа XML-документа (document type declaration) содержит определение типа документа (document type definition, DTD) или указывает на него. DTD — это специальная грамматика, описывающая синтаксис определенного класса документов; правила создания DTD рассмотрены в гл. 8.2. Здесь же приводится только описание деклараций, которые обеспечивают доступ к DTD. Декларация типа документа, как и декларация раздела, может быть внутренней или внешней. Внутренняя декларация имеет вид:
<!DOCTYPE имя [ тело ]>
а внешняя — те же два варианта, что и внешние разделы:
<!DOCTYPE имя SYSTEM URI [ тело ]>
<!DOCTYPE имя PUBLIC строка? URI [ тело ]>
Таким образом, отличие декларации типа документа от декларации раздела состоит только в том, что:
она начинается с ключевого слова !DOCTYPE, а не !ENTITY;
она может иметь тело, заключенное в квадратные скобки.
Имя такой декларации должно совпадать с именем корневого элемента, который она описывает, а тело должно соответствовать правилам построения DTD и будет описано в гл. 8.2. Пока отметим, что оно может содержать декларации разделов. Примеры внешних деклараций:
<!DOCTYPE spec SYSTEM "xml/1998/06/xmlspec-v20.dtd">
<!DOCTYPE spec PUBLIC "-//W3C//DTD Specification V2.0//EN"
"/XML/1998/06/xmlspec-v20.dtd">
Отметим, что внешняя декларация типа документа может содержать и ссылку на DTD, которая называется внешним подмножеством DTD, и тело, которое описывает дополнения к внешней DTD (оно называется внутренним подмножеством DTD).
Пример XML-документа
Чтобы собрать все описанные выше понятия в единое целое, приведем пример законченного XML-документа, содержащего прейскурант книжного магазина.