Деревья и узлы
Деревья и узлы
При работе с XSLT следует перестать мыслить в терминах документов и начать — в терминах деревьев. Дерево представляет данные в документе в виде множества узлов — элементы, атрибуты, комментарии и т.д. трактуются как узлы — в иерархии, и в XSLT структура дерева соответствует рекомендации XPath W3C (www.w3.org/TR/xpath). В данной главе мы рассмотрим деревья и узлы концептуально, а в главах 3 и 4 я дам формальное введение в XPath и его связь с XSLT. Выражения XPath, записываемые в терминах деревьев и узлов, используются для поиска данных в XML-документах.
В действительности, в соответствии с рекомендацией XSLT процессоры XSLT не обязаны уметь работать с документами; формально XSLT-преобразования принимают в качестве ввода исходное дерево и производят в качестве вывода результирующее дерево. В большинстве процессоров, тем не менее, существует дополнительная поддержка работы с документами.
Таким образом, с точки зрения XSLT документы представляют собой образованные из узлов деревья; XSLT распознает семь типов узлов:
• Корневой узел. Это самое начало документа. Этот узел представляет для процессора XSLT весь документ. Важно: не путайте корневой узел с корневым элементом, который также называется элементом документа (подробнее об этом мы поговорим позже в этой главе);
• Узел атрибута. Содержит значение атрибута после того, как были раскрыты ссылки на сущности и отброшены окружающие символы-разделители;
• Узел комментария. Содержит текст комментария, не содержащий символов <! и >;
• Узел элемента. Состоит из части документа, заключенной в открывающий и соответствующий ему завершающий теги, или единственный пустой элемент-тег, например <br/>;
• Узел пространства имен. Представляет объявление пространства имен. Обратите внимание: этот узел добавляется к каждому элементу, к которому применяется это пространство имен;
• Узел инструкции обработки. Содержит текст инструкции обработки, не содержащий символов <? и ?>. Скажем, объявление <?xml version="1.0"?> не является инструкцией обработки, несмотря на то, что выглядит таковой. Процессор XSLT отбросит его автоматически;
• Текстовый узел. Текстовые узлы содержат последовательности символов, То есть текст PCDATA. Текстовые узлы по умолчанию в XSLT подвергаются нормализации, то есть смежные текстовые узлы объединяются.
Как мы увидим в главе 7, для работы с деревьями и узлами используются выражения XPath. Выражение XPath возвращает единственный удовлетворяющий выражению узел, или множество узлов, если таких узлов несколько. XPath проектировался как средство навигации по деревьям — и, разобравшись с XPath, вы разберетесь с большей частью XSLT.
Важно помнить следующее: корневой узел дерева XSLT представляет весь документ. Это не то же самое, что корневой элемент. Взгляните, например, на следующий документ — в терминах XSLT корневой узел представляет документ целиком, а корневым элементом является <library>:
<?xml version="1.0"?>
<library>
<book>
<title>
Earthquakes for Lunch
</title>
<title>
Volcanoes for Dinner
</title>
</book>
</library>
Термин корневой элемент (root element) пришёл из рекомендации XML, и, поскольку его легко спутать с корневым узлом (root node) XSLT, пришедшим из рекомендации XPath, некоторые авторы, пишущие на тему XSLT, называют корневой элемент элементом документа. Очень жаль, что существует такое перекрытие терминов.
Вам следует также знать, что процессоры XSLT нормализуют текстовые узлы дерева, то есть объединяют два соседних текстовых узла в один большой текстовый узел для упрощения работы со структурой дерева документа. Поэтому, например, между двумя смежными узлами элементов никогда не будет более одного текстового узла, если изначально между этими узлами элементов располагался только текст.
В XSLT узлы могут иметь имена — так же, как дочерние узлы (child node) и родительские узлы (parent node). Иными словами, узлы элементов, атрибутов, пространств имен и инструкций обработки могут иметь имена; каждый узел элемента и корневой узел могут иметь дочерние узлы; и все узлы, за исключением корневого, имеют родителей.
Например, вот как выглядит рассмотренный нами ранее XML-документ в процессоре XSLT в виде дерева, состоящего из узлов:
root
|
element: <library>
|
element: <book>
|
|-------------------------------|
| |
element: <title> element: <title>
| |
text: "Earthquakes for Lunch" text: "Volcanoes for Dinner"
Как видим, корневой узел расположен на самом верху дерева, за которым следует узел корневого элемента, ему соответствует элемент <library>. За ним следует узел <book>, у которого есть два дочерних узла <title>. Эти два узла <title> являются внуками элемента <library>. Родители, дедушки и прадедушки узла, назад до и включая корневой узел, являются предками (ancestor) элемента. Узлы, производные от узла (дети, внуки, правнуки и т.д.), называются его потомками (descendant). Узлы одного уровня называются братьями (sibling).
При помощи этой модели в виде дерева можно представить любой хорошо сформированный XML-документ. Но XSLT не ограничивается работой только с такими документами. В хорошо сформированных документах должен существовать один элемент, содержащий все остальные, но в соответствии с рекомендацией XSLT это не обязательно. В XSLT корневой узел может иметь столько детей, сколько их может иметь элемент, — например, несколько узлов элементов или текстовых узлов. Таким образом, XSLT может работать с фрагментами документа, а не только с хорошо сформированными документами.
ФРАГМЕНТЫ РЕЗУЛЬТИРУЮЩЕГО ДЕРЕВА
Помимо работы с фрагментами входного дерева, процессоры могут включать в вывод специальный тип данных, в XSLT 1.0 называемый фрагментом результирующего дерева (result tree fragment). Этот тип данных, однако, не был включен в рабочий проект XSLT 1.1 (см. главу 7), поэтому он, скорее всего, не будет входить в состав XSLT 2.0.
В действительности, рассмотренная только что диаграмма дерева не дает полной картины того, как она выглядит с точки зрения процессора XSLT. Я исключил один тип узлов, который вызывает большую путаницу при изучении XSLT — текстовые узлы, содержащие только символ-разделитель (whitespace). Теперь самое время заняться ими.