Стилевые таблицы XSL

Стилевые таблицы XSL
== Язык XML. Стилевые таблицы XSL ==
В предыдущем разделе для вывода элементов XML- документа на экран броузера мы применяли Java Script-сценарии Однако, как уже отмечалось, для этих целей предпочтительней использование специально предназначенного для этого средства - стилевых таблиц XSL(Extensible Stylesheet Language).
Стилевыми таблицами (стилевыми листами) принято называть специальные инструкции, управляющие процессом отображения элемента в окне программы-клиента(например, в окне броузера). Предложенные в качестве рекомендация W3C, каскадные стилевые таблицы(CSS- Cascading Style Sheets [7]) уже больше года используются Web- разработчиками для оформления Web- страниц. Поддержка CSS наиболее известными на сегодняшний день броузерами Netscape Navigator(начиная с версии 4.0) и Microsoft Explorer(начиная с версии 3.0), позволила использовать стилевые таблицы для решения самого широкого спектра задач - от оформления домашней странички до создания крупного корпоративного Web-узла. Слово каскадные в определении CSS означает возможность объединения отдельных элементов форматирования путем вложенных описаний стиля. Например, атрибуты текста, заданные в тэге <body>, будут распространяться на вложенные тэги до тех пор, пока в них не встретятся стилевые описания, отменяющие или дополняющие текущие параметры. Таким образом, использование таблиц CSS в HTML было весьма эффективно - отпадала необходимость явного задания тэгов форматирования для каждого из элементов документа.
Являясь очень мощным средством оформления HTML- страниц, CSS- таблицы, тем не менее, не могут применяться в XML-документах, т.к. набор тэгов в этом языке не ограничен и использование статических ссылок на форматируемые объекты документа в этом случае невозможно.
Поэтому для форматирования XML- элементов был разработан новый язык разметки, являющийся подмножеством XML, и специально был предназначен для форматирования XML- элементов.
Некоторые его отличия от CSS: Во-первых, стилевые таблицы XSL позволяют определять оформление элемента в зависимости от его месторасположения внутри документа, т.е. к двум элементам с одинаковым названием могут применяться различные правила форматирования. Во-вторых, языком, лежащем в основе XSL, является XML, а это означает, что XSL более гибок, универсален и у разработчиков появляется возможность использования средства для контроля за корректностью составления таких стилевых списков(используя DTD или схемы данных) В-третьих, таблицы XSL не являются каскадными, подобно CSS, т.к. чрезвычайно сложно обеспечить "каскадируемость" стилевых описаний, или, другими словами, возможность объединения отдельных элементов форматирования путем вложенных описаний стиля, в ситуации, когда структура выходного документа заранее неизвестна и он создается в процессе самого разбора. Однако в XSL существует возможность задавать правила для стилей, при помощи которых можно изменять свойства стилевого оформления, что позволяет использовать довольно сложные приемы форматирования.
В настоящий момент язык XSL находится на стадии разработки в W3C[3] и в будущем, видимо, станет частью стандарта XML. Это означает, что использование этого механизма является наиболее перспективным способом оформления XML- документов. В текущем рабочем варианте W3C, XSL рассматривается не только как язык разметки, определяющий стилевые таблицы - в него заложены средства, необходимые для выполнения действий по фильтрации информации, выводимой в окно клиента, поиска элементов, сложного поиска, основанного на зависимостях между элементами и т.д. На сегодняшний день единственным броузером, поддерживающим некоторые из этих возможностей, является бэта-версия Internet Explorer 5.0, однако в самом ближайшем будущем, безусловно, XSL будет использоваться также широко, как сегодня стандартные тэги HTML.
В этом разделе мы рассмотрим упрощенную объектную модель XSL- документа, используемую в текущей версии XSL-конвертора Microsoft msxsl, и поэтому информацию, изложенную далее, нельзя считать описанием стандарта языка.
Все примеры, приводимые далее, могут быть проверены при помощи XSL- конвертора, свободно доступного на странице Mcrosoft www.microsoft.com/xml/xsl/
=== С чего начать ===
Принцип обработки XML- документов стилевыми таблицами заключается в следующем: при разборе XSL-документа программа-анализатор обрабатывает инструкции этого языка и каждому элементу, найденному в XML- дереве ставит в соответствие набор тэгов, определяющих форматирование этого элемента. Другими словами, мы задаем шаблон форматирования для XML- элементов, причем сам этот шаблон может иметь структуру соответствующего фрагмента XML-документа. Инструкции XSL определяют точное месторасположение элемента XML в дереве, поэтому существует возможность применять различные стили оформления к одинаковым элементам, в зависимости от контекста их использования.
В общем случае, XSL позволяет автору задавать параметры отображения элемента XML, используя любые языки, предназначенные для форматирования - HTML, RTF и т.д. В этом разделе мы будем использовать в качестве такого языка HTML, т.к. документы, созданные при помощи этого языка разметки могут просматриваться любой подходящей программой просмотра Web-страниц
=== Структура XSL- таблиц ===
Рассмотрим основные структурные элементы XSL, используемые, в частности, в конверторе msxsl, для создания оформления XML-документов.
== Правила XSL ==
XSL- документ представляет собой совокупность правил построения, каждое из которых выделено в отдельный блок, ограниченный тэгами <rule> и </rule>. Правила определяют шаблоны, по которым каждому элементу XML ставится в соответствие последовательность HTML- тэгов, т.е. внутри них содержатся инструкции, определяющие элементы XML- документа и тэги форматирования, применяемые к ним.
Элементы XML, к которым будет применяться форматирование, обозначаются в XSL дескриптором <target-element/>. Для указания элемента с конкретным названием (название элемента определяется тэгами, его обозначающими), т.е. определения класса элемента, можно использовать атрибут type="<имя_элемента>"
Вот пример простейшего XSL-документа, определяющего форматирование для фрагмента <flower>rose</flower> :
<xsl>
<rule>
<target-element type="flower"/>
<children/>
</rule>
</xsl>
Уже на этом примере можно проследить особенность использования стилевых таблиц: в любых правилах при помощи соответствующих элементов декларативно задается область, которая определяет фрагмент XML-документа, как мы чуть позже увидим, программа-анализатор заново проходит все элементы, начиная с текущего, всякий раз, когда в структуре XML- документа обнаруживаются новые вложенные элементы.
Инструкция <target-element> указывает на то, что данное правило определяет элемент. Параметром type="flower" задается название XML-элемента, для которого будет использоваться это правило. Программа-конвертор будет использовать HTML-тэги, помещенные внутри блока <rule></rule> для форматирования XML-элемента, которому "предназначался" текущий блок. В том случае, если для какого-то элемента XML шаблон не определяется, в выходной документ будут добавлены тэги форматирования по умолчанию (например, <DIV></DIV> )
Процесс разбора XSL-правил является рекурсивным, т.е. если у элемента есть дочерние элементы, то программа будет искать определения этих элементов, расположенных "глубже" в дереве документа. Указанием на то, что необходимо повторить процесс разбора XML документа, теперь уже для дочерних элементов, является инструкция <children/>. Дойдя до нее, анализатор выберет из иерархического дерева XML- элементов нужную ветвь и найдет в XSL-шаблонах правила, определяющие форматирование этих нижележащих элементов. В том случае, если вместо <children> мы укажем инструкцию <empty/>, программа закончит движение по данной ветви и возвратится назад, в родительское правило. При этом текущее правило никакой информации в выходном HTML-документе изменять не будет, т.к. <empty/> в данном случае означает, что содержимое элемента отсутствует.
Если в одном правиле <target-element> используется несколько раз, то инструкции по форматированию будут распространены на все описываемые внутри него XML-элементы, т.е. можно задавать единый шаблон форматирования для нескольких элементов одновременно:
<xsl>
<rule>
<target-element type="item1"/>
<target-element type="item2"/>
<target-element type="item3"/>
<children/>
</rule>
</xsl>
Ниже приведен пример более сложного XSL- описания, некоторые фрагменты которого будут пояснены позже.
XML-документ:
<?XML Version="1.0"?>
<documents>
<books>
<book id="Book1">
<title>Макроэномические показатели экономики
Римской Империи в период ее расцвета</title>
<author>Иван Петров</author>
<date>21.08.98</date>
</book>
<book id="Book2">
<title>Цветоводство и животноводство.
 Практические советы</title>
<author>Петр Сидоров</author>
<date>10.10.98</date>
</book>
</books>
<articles>
<article id="Article1">
<author>Петр Иванов</author>
<title>Влияние повышения тарифов оплаты за телефон
на продолжительность жизни населения</title>
<date>12.09.98</date>
</article>
</articles>
</documents>
Содержимое XSL-документа:
<xsl>
 <rule>
 <root/>
 <HTML>
 <BODY bgcolor="white">
 
 Library
 
 <children/>
 
 
 </BODY>
 </HTML>
 </rule>
 <rule>
 <element type="book">
 <target-element type="author"/>
 </element>
 
 
 <children/>
 
 
 </rule>
 <rule>
 <element type="article">
 <target-element type="author"/>
 </element>
 
 <children/>
 </rule>
 <rule>
 <target-element type="book"/>
 <children/>
 </rule>
 <rule>
 <target-element type="article"/>
 <children/>
 </rule>
 <rule>
 <target-element/>
 <children/>
 </rule>
 <rule>
 <target-element type="books"/>
 Books
 <children/>
 </rule>
 <rule>
 <target-element type="articles"/>
 Articles
 <children/>
 </rule>
</xsl>
== Корневое правило ==
Разбор любого XSL- документа всегда начинается с правила для корневого элемента, в котором определяется область всего разбираемого XML документа и поэтому тэги форматирования, помещенные сюда, будут действовать на весь документ в целом. Для обозначения корневого правила необходимо включить в него элемент <root/>. Например, для того, чтобы задать тэг <body> для формируемой нами выходной HTML- страницы, мы можем использовать следующий фрагмент:
<xsl>
<rule>
<root/>
<html><head><title> Flowers</title></head>
<body bgcolor="white" link="blue" alink="darkblue" vlink="darckblue">
<children/>
</body>
</html>
</rule>
</xsl>
В этом примере при помощи инструкций <root/> и <children/> мы определили ряд начальных и конечных HTML-тэгов для нашей страницы, между которыми затем в процессе рекурсивного обхода XSL- анализатора будут помещены остальные элемента документа.
В том случае, если мы не определяем правило для корневого элемента, разбор документа начнется с первого правила с инструкцией <target-element> (для оформления же заголовка документа будет использован образец форматирования, применяющийся по умолчанию).
== Отношения между элементами ==
Дочерние элементы в XML-документе всегда находятся внутри области, определяемой тэгами родительского по отношению к ним элемента. Для того, чтобы точно указать месторасположение обрабатываемого элемента в дереве XML, в XSL используется дополнительный тэг <element>. При помощи него можно указать, какие элементы должны предшествовать текущему, а какие - следовать после него. Например, в следующем фрагменте определяется, что форматирование элемента <title> будет зависеть от его месторасположения внутри XML-документа:
<xsl>
<rule>
 <element type="journal">
 <target-element type="title"/>
 </element>
 
 
 <children/>
 
 
</rule>
<rule>
 <element type="article">
 <target-element type="title"/>
 </element>
 
 <children/>
 
</rule>
</xsl>
Как видно из примера, если в XML- документе будет найден элемент <title>, являющийся дочерним по отношению к элементу <article> (название статьи), то его форматирование будет несколько отличаться от элемента <title>, расположенного внутри тэгов <journal>
== Приоритеты правил ==
В том случае, если внутри XSL- документа встречается несколько правил для одного и того же элемента, то msxsl будет использовать то из них, которое более точно определяет позицию данного элемента. Т.е. если XSL- документ содержит следующие правила:
<rule>
 <element type="journal">
 <target-element type="title"/>
 </element>
 
 
 <children/>
 
 
</rule>
<rule>
 <target-element type="title"/>
 
 <children/>
 
</rule>
, то при использовании этой стилевой таблицы в случае, когда элемент <title> является потомком <journal>, к нему будет применено первое правило. Для любых же других элементов будет действовать правило без тэга <element>
В общем случае приоритет правил определяется следующим образом (в порядке убывания приоритета):
* правила, помеченные специальным тэгом <importance> 
* правила с наибольшим значением атрибута id, если он определен 
* правила с наибольшим значением атрибута class, если он определен 
* правила, имеющие наибольшую вложенность, определяемую тэгом <element> 
* правила, использующие атрибут type совместно с <target-element> 
* правила, в которых отсутствует атрибут type в <target-element> или <element> 
* правила с более высоким приоритетом, задаваемым атрибутом priority тэга <rule> 
* правила с наибольшим значением квалификаторов <only>, <position>, <attribute> 
== Использование атрибутов элементов ==
Применительно к <target-element> и <element> в правилах также могут использоваться специальные элементы <attribute>, при помощи которых можно уточнять характеристики обрабатываемых элементов, задавая различные инструкции форматирования для одинаковых элементов с различными атрибутами. Указываемые в <attribute> параметры name и value определяют атрибут XML, который должен иметь текущий обрабатываемый элемент. Например, в следующем фрагменте все элементы с атрибутом free_lance = "true" будут выделены в выходном HTML- документе серым цветом
<rule>
 <target-element type="author">
 <attribute name="free_lance" value="true">
 </target-element>
 
 <children/>
 
</rule>
== Фильтрация элементов ==
Одним из самых мощных средств XSL является возможность сортировки и выборки элементов, выделяемых из общего дерева элементов документа. Для этого используется элемент <select-elements>, который заменяет <children/> в правилах, определяя те элементы, которые следует обработать в процессе рекурсивного обхода. Например, в следующем примере будут обработаны только элементы <author>:
<rule>
<target-element type=" staff"/>
<select-elements>
<target-element type = "author"/>
</select-elements>
</rule>
Элемент <select-elements> сам по себе не определяет шаблон форматирования, он лишь управляет работой анализатора, обозначая, подобно <children/>, "нижележащие" элементы. В приведенном примере элемент <author> должен быть расположен внутри элемента <staff>.
Для того, чтобы в шаблоне выделить не только собственные дочерние элементы, но и дочерние элементы потомков, т.е. использовать несколько уровней вложенности, необходимо задать параметр from = "descendants". Если параметр имеет значение "children", что указывает на то, что выбор должен производится из списка собственных дочерних элементов, то атрибут from может опускаться, т.к. "children" является значением по умолчанию.
== Правила стилей ==
В отличие от CSS, в XSL невозможно использование каскадных стилевых определений(т.е. нельзя использовать несколько правил для определения стиля одного того же элемента), т.к. такие ограничения вводит рекурсивный алгоритм работы программы - анализатора. Однако использование правил определения стиля(Style Rules) элемента позволяет каким-то образом скомпенсировать этот недостаток.
Для определения правила стилевого оформления необходимо воспользоваться элементом <style-rule>, который используется точно также, как и <rule>, но инструкции, содержащиеся в нем, никак не влияют на структуру выходного документа. Поэтому все команды внутри этого правила должны описываться в рамках элемента <apply>. Вот как будет выглядеть, например, определение стиля для элемента <flower>rose</flower>:
<style-rule>
<target-element type ="flower"/>
<apply color ="red"/>
</style-rule>
<rule>
<target-element type="flower"/>
<children/>
</rule>
Если бы мы не определили правила <rule>, то в выходной документ не было бы помещено никакой информации, т.к. элемент <style-rule> только определяет параметры стилевого оформления, не предпринимая никаких других действий.
Также надо учитывать, что XSL-анализатор использует CSS для определения задаваемого правилами <style-rule> стиля в выходном HTML-документе, тем самым предоставляя нам возможность использования этого мощного средства при оформлении HTML-страниц После обработки приведенного в примере фрагмента в выходной документ будут помещены следующие элементы:
rose
Еще один пример:
Стили в формате CSS:
issue {font-weight=bold; color=blue;}
.new {font-weight=bold; color=red;}
Фрагмент XSL- документа, позволяющего использовать подобные стилевые определения:
<style-rule>
<target-element type ="issue"/>
<apply color ="blue"/>
</style-rule>
<style-rule>
<target-element type ="issue">
<attribute name ="class" value ="new" />
</target-element>
<apply color ="red"/>
</style-rule>
<rule>
<target-element type="issue"/>
<children/>
</rule>
== Сценарии ==
Сценарии могут использоваться в документах XSL точно также, как и в HTML. Кроме того, сценарии, содержащиеся внутри XSL-документа и запускаемые броузером в процессе обработки документа могут динамически создавать HTML-документы, извлекая необходимую для этого информацию непосредственно из элементов XSL-документа.
Для написания сценариев XSL использует специальный скриптовый язык - ECMAScript. Однако в msxsl для этих целей можно применять Microsoft JavaScript,- язык, который объединил в себе некоторые элементы стандартного JavaScript и ECMAScript.
== Вычисление выражений ==
Наиболее простым примером использования сценариев в XSL -документе является вычисление значений параметров описываемых элементов. Для этого надо просто поставить знак равенства в качестве первого символа параметра, что заставит XSL-процессор вычислить значение выражения(синтаксис этого выражения должен отвечать требованиям JavaScript). Например, после разбора этого правила:
<rule>
<target-element type="header">
<children/>
</rule>
, в выходном документе окажутся следующие инструкции:
...
Очень часто в правилах XSL необходимо использовать атрибуты описываемого в них элемента. Для этого мы должны воспользоваться методом getAttribute(), описанным в объектной модели XML (мы рассматриваем объектную модель XML-документов, предложенную Microsoft, список этих функций приведен в конце раздела). Т.к. каждому элементу XSL доступен указатель на соответствующий ему объект, сценарий может обращаться к внутренним функциям и свойствам этих элементов, при помощи которых и осуществляются необходимые действия.
В следующем фрагменте XML- документа определяется элемент <article>, в котором атрибут src используется для задания адреса файла, содержащего текст статьи.
<articles>
<article src="http://server/pages/article.html">Bugs report</article>
</articles>
Для того, чтобы использовать этот атрибут в выходном HTML-документе, необходимо определить следующее правило:
<rule>
<target-element type="article">
<a href='=getAttribute("src")'>
<children/>
</a>
</rule>
После обработки этого фрагмента в выходной документ будет помещен элемент:
<a href="http://server/pages/article.html">Bugs report</a>
== Выполнение инструкций ==
Другим способом помещения в выходной HTML- документ информации, являющейся результатом выполнения каких-либо операций JavaScript - сценариев является использовнаие инструкции <eval>:
<rule>
<element type="articles">
<target-element type="article">
</element>
<eval>childNumber(this)</eval>
<children/>
</rule>
Метод childNumber в данном случае возвращает текущий номер дочернего элемента.
== Определение функций и глобальных переменных ==
Аналогично тэгу <SCRIPT> в HTML, элемент <define-script> содержит функции и определения глобальных переменных. Обычно в XSL-документе определяется один элемент <define-script>, расположенный в самом начале.
<xsl>
<define-script>
<![CDATA[
var fontSize=12;
function getColor(elem){
return elem.children.item("color",0).text;
 // Возвращает содержимое дочернего элемента <color>
}]]>
</define-script>
<rule>
<target-element type = "flower">
<children/>
</rule>
</xsl>
Если применить эти правила к такому фрагменту XML- документу:
<xml>
<flower>
rose
<color>red</color>
</flower>
, то на выходе HTML -документ будет содержать следующие элементы:
Необходимо отметить, что использование глобальных переменных в некоторых случаях может приводить к серьезным ошибкам, вызванным попытками одновременного к ним доступа. Поэтому рекомендуется использовать такие переменные только в качестве констант.
== Использование Java Script для HTML ==
Создавая шаблон HTML-документа, Вы можете указывать в нем практически любые элементы HTML, в том числе и блоки <SCRIPT>, внутри которых можно задавать любые конструкции Java Script, используя для этого область CDATA:
<xsl>
 <rule>
 <root/>
 <HTML>
 <HEAD>
 <SCRIPT LANGUAGE="JSCRIPT"><![CDATA[
var ie4=((navigator.appName=="Microsoft Internet
Explorer")&&(parseInt(navigator.appVersion) >= 4 ));
 function msover(){
if (ie4){
 event.srcElement.style.color="red";
 event.srcElement.style.cursor = "hand";
 }
}
 function msout(){
 if (ie4){
 event.srcElement.style.color="black";
 event.srcElement.style.cursor = "auto";
 }
} ]]></SCRIPT>
 </HEAD>
 <BODY>
 <children/>
 </BODY>
 </HTML>
 </rule>
 <rule>
 <target-element type="chapter"/>
 <DIV id='=tagName + formatNumber
 (childNumber(this),"1")'
 background-color="marron"
 onmouseover='="msover("+ tagName +
 formatNumber(childNumber(this),"1")+")"'
 onmouseout='="msout("+ tagName +
 formatNumber(childNumber(this),"1")+")"'
 <children/>
 </DIV>
 </rule>
</xsl>
Если использовать эти правила для следующего XML- документа:
<contents>
 <chapter>Part1</chapter>
 <chapter>Part2</chapter>
 <chapter>Part3</chapter>
</contents>
то в результате мы получим такой HTML-файл:
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JSCRIPT">
var ie4=((navigator.appName=="Microsoft Internet
Explorer")&&(parseInt(navigator.appVersion) >= 4 ));
function msover(){
if (ie4){
 event.srcElement.style.color="red";
 event.srcElement.style.cursor = "hand";
 }
}
function msout(){
 if (ie4){
 event.srcElement.style.color="black";
 event.srcElement.style.cursor = "auto";
 }
 }
</SCRIPT>
</HEAD>
<BODY>
<DIV id=chapter1" onmouseover="msover("chapter1")"'
 onmouseout="msout("chapter1")"'
 Part 1
 </DIV>
<DIV id=chapter2" onmouseover="msover("chapter2")"'
 onmouseout="msout("chapter2")"'
 Part 2
 </DIV>
<DIV id=chapter3" onmouseover="msover("chapter3")"'
 onmouseout="msout("chapter3")"'
 Part 3
 </DIV>
</BODY>
</HTML>
== Встроенные функции XSL ==
В завершении приведем список внутренних функций, которые можно использовать в JavaScript -сценариях, предназначенных для анализатора msxsl:
Ancestor(elementType, elem) 	Возвращает для текущего элемента ссылку на ближайший родительский элемент заданного типа. Если такого элемента нет или текущий элемент пустой, то возвращает null
ChildNumber(elem) 	Возвращает индекс текущего элемента в списке других дочерних элементов данного типа.
AncestorChildNumber() 	Возвращает номер ближайшего предка текущего элемента или null, если такового не существует
path(xsl) 	Возвращает массив, содержащий "путь" к текущему элементу - в каждую ячейку этого массива помещается цифровое значение, указывающее на количество элементов одинакового типа, находящихся на текущем уровне вложенности. Первым значением этого массива будет представлен корневой элемент, последним - текущий. Размер массива определяет глубину вложенности текущего элемента.
HierarchicalNumberRecursive (elementType,elem)	Метод, похожий на метод path, но возвращает только дочерние элементы
FormatNumber(n,format) 	Возвращает строку - символьное представление номера(т.е. "один", "два" и т.д.). Возможно определение следующих форматов: "1" - 0,1,2,.. "01" - 01,02,03,... "a" - a,b,c,..z, aa, ab,..zz "A" - A,..,Z,AA, .. ZZ
FormatNumberList(list,format,separator) 	Возвращает строку, представляющую список, элементами которого являются символьные представления чисел
Source: http://helper10.narod.ru/
ID: 03111
Category:XML
Category:Статьи