1.2 Основы XML
Почти всё, что мы делаем в этой книге делается с XML-документами. XSLT преобразования сами по себе являются XML-документами, и они задуманы, чтобы трансформировать XML-документ в нечто другое. На тот случай, если вы не имеете большого опыта в XML, мы рассмотрим здесь основы.
1.2.1 Наследие XML
XML — это наследие SGML. Созданный доктором Чарльзом Голдфабом (Dr. Charles Goldfarb) в 1970х, SGML широко используется в высококлассных издательских системах. К сожалению, сложно воспринимающийся SGML не достиг широкого признания в индустрии. SGML очухался (:-)), когда Тим Бернс-Ли (Tim Bernes Lee) построил HTML на основе SGML. Буквально наутро вся компьютерная индустрия стала использовать язык разметки для создания документов и приложений.
Проблема HTML была в том, что его теги были разработаны для взаимодействия между людьми и машинами. Это было отлично для подзних 1980х, когда был придуман web. С тем как web продвигался во все аспекты нашей жизни, к HTML возникло множество необычных вопросов. Мы строили все HTML-страницы с неуклюжей табличной структурой, 1-пиксельными gif`ами и другими бессмыслицами, только чтобы получить страницу, правильно выглядящую в браузере. XML разработан, чтобы вытащить нас из этой ямы и вернуть в мир структурированных документов.
Каковы бы ни были ограничения, HTML самый популярный когда либо созданный язык разметки. Имея его популярность, зачем нам понадобился XML? Рассмотрим этот чрезвычайно информативный HTML-элемент:
Что символизирует этот очаровательный кусочек кода?
- Это почтовый индекс Скенектади в Нью Йорке?
- Это число лампочек, заменяемых каждый месяц в Лас Вегасе?
- Это число Вольцвагенов, проданных в Гон Конге в прошлом году?
- Это число тонн стали Сиднейского Моста?
Можеть быть да, может быть нет. Чревоточинка этого глупого примера в том, что тут нет структуры данных. Даже если бы мы привели целую таблицу, требуется сообразительность, чтобы уловить смысл этих данных. Если бы вы увидели эту ячейку в таблице следующей за другой ячейкой, которая содержит текст «Скенектади», и озаглавленную выше «Почтовын индексы штата Нью Йорк», как человек, вы можете толковать содержание этой ячейки правильно. С другой стороны, если бы вы хотели написать кусок кода, который брал бы некоторую HTML-таблицу и попытались бы определить, содержат ли какие-нибудь ячейки в таблице почтовые индексы, вы поняли бы, что это очень сложно, если не невозможно.
Большинство HTML-страниц имеют одну желаемую цель — выведение документа. Ветераны индустрии разметки знают, что это точно не путь создания содержания. Разделение содержания и представления — укоренившийся принцип издательской индустрии; к сожалению, множество HTML-страниц не приближаются к этому идеалу. XML-документ должен содержать информацию, маркированную при помощи тегов, которые описывают, что это за кусочки информации и взаимосвязь между этими частями. Представление документа (или — отрисовка) включает в себя правила и решения, отделённые от самого документа. Поскольку мы работаем c массой документов и приложений, вы увидите, как откладывание окончательной отрисовки настолько, насколько возможно, даёт значительное преимущество.
Давайте посмотрим на ещё один размеченный документ. Внимайте:
<postalcode>
<title>Most-used postal codes in November 2000</title>
<item>
<city>Schenectady</city>
<postalcode>12304</postalcode>
<usage-count>2039</usage-count>
</item>
<item>
<city>Kuala Lumpur</city>
<postalcode>57000</postalcode>
<usage-count>1983</usage-count>
</item>
<item>
<city>London</city>
<postalcode>SWIP 4RG</postalcode>
<usage-count>1722</usage-count>
</item>
...
</postalcode>
Несмотря на то, что мы всё ещё в сфере выдуманных примеров, будет довольно легко написать кусок кода, чтобы искать почтовые индексы в любом документе, который использовал такие теги (по сравнению с тегами HTML: <table>, <tr>, <td> и т.д.) Наш код будет высматривать содержание какого бы то ни было элемента <postalcode> в документе. Хорошо спроектированный XML-документ идентифицирует каждый кусочек данных в документе и моделирует взаимоотношения между двумя кусочками. Это означает, что вы можете быть уверены, что мы обрабатывается XML-документ корректно.
Кроме того, ключевая идея в том, что мы отделяем содержание от представления. Наш XML -документ ясно очерчивает кусочки данных и даёт их в формате, который легко распознать. В этой книге мы покажем ряд методик для преобразования этого XML-документа во многообразие форматов. Между прочим, мы можем преобразовать элемент <postalcode>12304</postalcode> в <td>12304</td>
1.2.1 Правила XML-документа
В нашей экскурсии по основам XML встречаются некоторые правила, которые вам надо держать в голове, создавая XML-документы. Все преобразования, которые мы разрабатываем в этой книге, ами по себе являются XML-документами, так что все правила XML-документов применимы ко всему, что мы делаем. Правила по-хорошему просты, и абсолютное большинство HTML-документов не следуют им.
Один важный пункт: спецификация XML 1.0 ясно показывает, что когда XML-парсер находит XML-документ, который отклоняется от правил, парсер обязуется выдать исключение или остановиться. Парсеру не позволяется ломать голову, какой на самом деле должна быть структура документа. Эта спецификация предостерегает от воссоздания ситуации с HTML, когда множество безобразных документов всё же отрисовываются обычным браузером.
1.2.2.1 XML-документ должен быть заключен в единственный элемент
Первый элемент в вашем XML-документе должен содержать полный документ. Этот первый элемент называется document element или root element (корневой элемент). Если в документе больше одного корневого элемента, XML-парсер выдаст исключение. Этот XML-документ совершенно правильный:
<greeting>
Hello, World!
</greeting>
(Будучи точными, этот документ «по форме». XML-документы характеризуются как «по форме» и «правомерные» (валидные); мы скоро определим эти термины.) А этот XML-документ неверный:
<greeting>
Hello, World!
</greeting>
<greeting>
Hey, Y`all!
</greeting>
В этом документе два корневых элемента, так что парсер XML откажется разбирать его. Кроме того, учтите, что XML-декларация (строка <?xml version="1.0"?>, скоро мы о ней поговорим) не является элементом вообще.
1.2.2.2 Элементы должны быть вложенными
Если вы вводите один элемент внутрь другого, вы должны закрыть его здесь же. HTML-браузер счастлив отрисовать такой документ:
Но парсер XML будет выдавать исключение, когда ему попадётся этот документ. Если вы хотите подобного эффекта, вы должны написать код так:
1.2.2.3 Атрибуты заключаются в кавычки
Вы можете заключать атрибуты в двойные или одинарные кавычки. Следующие два XML-тега эквивалентны:
<a href="http://yandex.ru"></a>
Если вам нужно определить атрибут со значением, вы можете использовать одинарные кавычки внутри двойных. Если вам нужны и те, и другие кавычки внутри значения атрибута, используйте мнемо-подстановки " для двойных кавычек и ' для одинарных.
Небольшое замечание: XML не допускает атрибутов без значений. Другими словами, HTML-элемент наподобии <ol compact> не валиден в XML. Чтобы задать этот элемент в XML, вы должны присвоить атрибуту значение, например <ol compact="yes">.
1.2.2.4 XML-теги регистрозависимы
В HTML <h1> и <H1> — одно и то же. В XML не так. Если вы попытаетесь закрыть элемент <h1> при помощи тега </H1>, парсер выдаст исключение.
1.2.2.5 Требуются закрывающие теги
Это ещё один аспект, где большинство HTML-документов ломаются. Ваш браузер не беспокоится, если у вас нет тегов </p> или </br>, в отличие от парсера XML.
1.2.2.6 Пустые теги могут содержать закрывающий маркеp
Другими словами, эти два XML фрагмента идентичны:
<lily age="6"/>
Предупреждаю, что нет ничего, даже пробела, между открывающим и закрывающим тегами в первом примере; так что это делает его пустым тегом.
1.2.2.7 XML декларация Некоторые XML-документы начинаются с XML-декларации.
XML-декларация — это строчка подобная этой:
Если не установлена кодировка, XML-парсер прдполагает, что вы используете UTF-8, Юникод стандарт, который использует разное число байт, чтобы эффективно представлять каждый символ и условный знак из мировых языков. Знайте, что каждый парсер поддерживает различный ряд кодировок, так что вам нужно свериться с документацией вашего парсера, чтобы убедиться, каковы ваши настройки.
1.2.2.8 Определение типов документа (Document Type Definitions, DTDs) и XML-схемы
Все правила, которые мы обсуждали до сих пор, применяются ко всем XML-документам. В добавок, вы можете использовать DTDs и схемы, чтобы определить другие рамки для ваших XML-документов. DTD и Схемы — это метаязыки, которые дают вам возможность определять характеристики XML-терминологии. Например, вы хотели бы определить, что некоторый XML-документ, описывающий список покупок, должен начинаться с элемента <po>, и элемент <po> в свою очередь включает в себя элемент <customer-id>, один или несколько элементов <item-ordered> и элемент <order-date>. В добавок, каждый элемент <item-ordered> должен включать атрибуты part-number и quantity.
Вот пример DTD-схема, которая определяет ограничения только что упомянутые нами:
<!ELEMENT po (customer-id , item-ordered+ , order-date)>
<!ELEMENT customer-id (#PCDATA)>
<!ELEMENT item-ordered EMPTY>
<!ATTLIST item-ordered part-number CDATA #REQUIRED
quantity CDATA #REQUIRED >
<!ELEMENT order-date EMPTY>
<!ATTLIST order-date day CDATA #REQUIRED
month CDATA #REQUIRED
year CDATA #REQUIRED >
А это XML Schema, которая определяет тот же самый тип документа:
<xsd:schema xmlns:xsd="http://www.w3.org/2000/10/XMLSchema">
<xsd:element name="po">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="customer-id"/>
<xsd:element ref="item-ordered" maxOccurs="unbounded"/>
<xsd:element ref="order-date"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="customer-id" type="xsd:string"/>
<xsd:element name="item-ordered">
<xsd:complexType>
<xsd:attribute name="part-number" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{5}-[0-9]{4}-[0-9]{5}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="quantity" use="required" type="xsd:integer"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="order-date">
<xsd:complexType>
<xsd:attribute name="day" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:integer">
<xsd:maxInclusive value="31"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="month" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:integer">
<xsd:maxInclusive value="12"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="year" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:integer">
<xsd:maxInclusive value="2100"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Schema имеет значительные преимущества перед DTD:
- Она может описывать типы данных и другие сложные структуры, что сложно или невозможно сделать в DTD. В предыдущем примере мы определили различные ограничения для данных в нашем XML-документе. Мы определили, что атрибут day может иметь целочисленное значение от 1 до 31, а атрибут month может быть целым числом от 1 до 12. Мы также использовали регулярное выражение, чтобы определить значение атрибута part-number как комбинацию: пятизначное число, тире, четырёхзначное число, тире, другое пятизначное число. Ни одна из этих вещей не возможна в DTD.
- Shema сама по себе XML-документ. А так как это XML-документы, мы можем написать XSLT-инструкции, чтобы управлять ими. Сейчас есть приложения, которые берут схему и составляют XML-документ на её основе. Рисунок 1.1 показывает пример, составленный по нашей схеме.
Генерирование результата сравнительно прямолинейное, потому что инструмент преобразует XML-документ. Схема определяет многообразие элементов, атрибутов и ограничений правильных данных, всё это без труда может быть преобразовано в другие форматы, такие как HTML, показанный на Рисунке 1.1.
1.2.2.9 Хорошо согласованные отличия правильных документов
Любой XML-документ, который следует описанным здесь правилам, называется хорошо согласованным. В добавок, если XML-документ ссылается на ряд правил, которые определяют как документ структурирован (либо DTD, либо Schema) и следует всем тем правилам, он называется корректным (valid).
Корректные документы хорошо структурированы; с другой стороны, не все хорошо структурированные документы корректны.
1.2.2.10 Теги отличаются от элементов
Хотя многие люди используют эти два термина равнозначно, тег (tag) отличается от элемента. Тего — это текст между угловыми скобками (< and >). Есть открывающие, закрывающие и пустые теги. Тег состоит из имени и, если это открывающий или пустой тег, необязательных атрибутов. (В отличие от других языков разметки, в XML закрывающий тег не может содержать атрибуты.) Элемент состоит из открывающего тега, закрывающего тега и всего, что находится между ними. Это подразумевает включение текста, других элементов, комментариев, а также других вещей как указание сущности (entity) и обрабатываеющие инструкции.
1.2.2.11 Простраства имён
Заключительная тема об XML, которую мы упомянем здесь — это пространства имён (namespaces). Пространства имён придуманы, чтобы различать два тега с одинаковыми именами. Например, если я составляю XML-словарь для книг, а вы делаете то же самое для живописи, получится похоже, потому что мы оба определим эелмент <title>. Пространства имён определяются и используются следующе:
xmlns:paintings="http://www.yourco.com/paintings.xsd">
В этом примере атрибут xmlns:books связывает строку с DTD books.dtd, а атрибут xmlns:painting связывает строку со схемой painting.xsd. Это значит, что элемент title из DTD books будет определён как <books:title>, а элемент title из схемы paintings будет отнесён к <painting:title>.
Я упоминаю здесь пространства имён главным образом потому что все XSLT-элементы, которые мы используем в этой книге начинаются с префикса xsl. Все написанные нами преобразования начинаются с подобного:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
Это вступление связывает префикс пространства имён xsl со строкой . Значение пространсва имён не имеет значения, вы могли бы начинать свою таблицу стилей с чего-нибудь вроде этого:
<pdq:stylesheet
xmlns:pdq="http://www.w3.org/1999/XSL/Transform"
version="1.0">
Эти сущности — строки, согласно которым префикс пространства имён отображается. Также имейте в виду, что все таблицы XSLT-преобразований используют префиксы пространств имён, чтобы обрабатывать XML-елементы, которые они содержат. По умолчанию то, что не использует префикс xsl не обрабатывается — это записано в результирующее дерево. Мы будем обсуждать эти темы более детально далее в книге.
Tags: xml/xsl