XML-XSL технология для построения интернет сайта
|
6 Специфика XSL преобразований
Язык XSL преобразований – непроцедурный, такие языки еще
называют декларативными или функциональными.
Существуют разные непроцедурные языки программирования, например РЕФАЛ,
предложенный В.Ф. Турчиным. Одна из специфик XSL преобразований – это их ориентация
на обработку XML файлов. XSL преобразования применяются только к XML файлам и состоят из шаблонных
правил, которые соответствуют тегам просматриваемого XML файла.
В принципе преобразования XML файлов как текстовых файлов можно писать
на любом языке программирования, но язык XSL
специально придуман для технологии обработки XML файлов – XSL преобразование всегда строит
правильные XML объекты из правильных XML объектов.
В XSL преобразовании не описывается
последовательность действий над XML документом.
Применение преобразования состоит в том, что XML документ (входной XML документ) определенным образом просматривается, а когда встречается какой-либо тег этого XML документа, то применяется соответствующее шаблонное правило из XSL преобразования.
Шаблоны в XSL преобразовании выглядят как <xsl: template match(“thetag”)>. Содержимое такого шаблона
языка XSL говорит о том, какие действия надо совершить, встретив при просмотре
тег с названием “thetag”. В частности что-то может выводиться в выходной файл, который тоже
обязательно является XML документом. Само XSLT преобразование – тоже XML документ.
Конечно, входной файл – это один XML язык, выходной – это другой XML язык, а XSL преобразование переводит файлы
одного языка в файлы другого. В нашем случае входной XML файл – нами созданное описание страницы, а
выходной – HTML страница, точнее – более строгий вариант XHTML. В процессе обработки XML файла XSL преобразование может брать и обрабатывать информацию из других XML файлов (это показано в примерах следующего
параграфа)
«Непроцедурность» XSL преобразования в некоторых случаях может делать это
преобразование «дополняемым» или
«расширяемым» (подробнее об этом в параграфе 7).
Расширяемость
здесь значит следующее. Если
при расширении языка описания страницы мы вводим новые теги (для описания новых элементов страницы),
то XSL преобразование просто
дополняется тегами <XSL template match(“thetag”)> для вновь введенных тегов “thetag”.
Дополнения можно делать даже в
отдельном файле, используя include.
Мы проиллюстрируем «расширяемость» XML-XSL технологии на двух примерах в следующих параграфах. Первый пример показывает, как можно расширить очень простой язык описания страницы, второй пример касается меню и его английского варианта (для
английской версии страницы),
Приведем несколько совсем простых примеров XSL преобразований. Примеры чисто
иллюстративные и показывают принципы работы XSL процессора.
XSL преобразование – это XML файл, теги которого имеют вид <xsl: …….> и выполняют функции операторов языка. Так
называемый XSL процессор – программа,
выполняющая или интерпретирующая XSL преобразования, – на входе получает один XML файл и одно XSL преобразование (тоже XML файл). Преобразование применяется
к файлу, на выходе получаем третий XML файл. XSL процессор просматривает входной XML
файл по стандартным правилам (такой просмотр называется парсингом).
Начинается просмотр с корневого тега /. Рассматривая какой-то тег, XSL процессор применяет шаблон для этого
тега. В шаблоне указывается, что надо
выводить в выходной файл, и как дальше просматривать теги входного
файла. Шаблон этого тега берется из файла XSL преобразования. А если шаблона для рассматриваемого тега в XSL
преобразовании нет, то работает шаблон по умолчанию: текстовое
содержимое тега просто переписывается в выходной файл и начинается
последовательный (точнее, рекурсивный) просмотр вложенных тегов.
Например, как работает XSL процессор на пустом XSL
преобразовании?
<?xml version="1.0"
encoding="windows-1251"?>
<xsl L:transform version="1.0"
xmlns:
xsl
="http://www.w3.org/1999/XSL/Transform">
</xsl:transform>
Никаких шаблонов в преобразовании нет, поэтому любой тег XSL процессор обрабатывает шаблоном по
умолчанию. Результатом применения такого преобразования к любому XML файлу будет записанное последовательно
(точнее рекурсивно – в порядке просмотра тегов) текстовое содержимое всех тегов
данного файла. Например, результатом преобразования такого файла
<file>
aaa
<tag1>bbb
<tag2>ccc</tag2>
fff
</tag1>
<tag3>ddd</tag3>
<tag2>ccc</tag2>
</file>
будет последовательность aaabbbcccfffdddccc.
Но XSL-преобразование
может переопределить совершаемые
по умолчанию действия XSL процессора.
Такие переопределения называются шаблонами и записываются
как <xsl:template match=”xxx”>ТЕЛО ШАБЛОНА</ xsl:template>. Шаблон может записывать что-то
в выходной файл. Кроме этого он определяет порядок дальнейшего просмотра вложенных тегов. Например, вызов
<xsl:call-templates select=”thetag”> говорит о том, что должны вызываться
шаблоны только для тегов thetag, непосредственно вложенных в текущий
тег.
Например, в XSL преобразовании определим шаблон для корневого элемента XML файла, но этот шаблон
оставим просто пустым.
<?xml version="1.0"
encoding="windows-1251"?>
<xsl:transform version="1.0" xmlns: xsl ="http://www.w3.org/1999/
xsl/Transform">
<xsl:template match="/">
</xsl:template>
</xsl:transform>
Применяя это преобразование к XML
файлу, мы получим пустой выходной файл:
шаблон первого – корневого – тега теперь
уже есть (в отличие от преобразования выше), но он просто пустой, и
поэтому никаких действий XSL процессор не совершает (ничего не
запишет в выходной файл и не будет рассматривать вложенные теги).
Расширим пустой шаблон корневого тега вызовом вложенных шаблонов
< xsl:apply-templates
select="*"/>.
<?xml version="1.0"
encoding="windows-1251"?>
<xsl:transform version="1.0"
xmlns:XSL="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:transform>
Это преобразование опять записывает в выходной XML файл текстовое содержание всех
тегов входного XML файла – шаблон корневого тега вызывает все шаблоны
вложенных тегов (за такой вызов отвечает select=”*”). Но шаблонов для вложенных тегов нет. Поэтому
применяются шаблоны по умолчанию, то есть всегда выводится текстовое содержимое тега. По
умолчанию осуществляется переход и к вложенным тегам.
Еще один пример – вызываем не все шаблоны, а только шаблоны одного тега <thetag> (где бы они не находились во
входном XML файле).
<xsl:transform version="1.0" XMLns:
xsl
="http://www.w3.org/1999/XSL/Transform">
< xsl:template match="/">
< xsl:apply-templates select="//thetag"/>
</ xsl:template>
</ xsl:transform>
Выражение select="//thetag"/> означает, что XSL процессор, просматривая исходный XML файл просто
игнорирует теги, не совпадающие с тегом
<thetag>.
Встретив же такой тег <thetag>,
XSL
процессор применяет шаблон по умолчанию, поскольку шаблона для этого тега в
преобразовании нет. То есть выводит текстовое содержимое этого тега и переходит
к вложенным в <thetag>
тегам, уже дальше никакие теги не игнорируя. Из них он опять берет только их
текстовое содержимое (опять шаблон по умолчанию). Результат этого преобразования –
записанное последовательно (рекурсивно) содержимое всех тегов <thetag>,
а также тегов, в них вложенных.
А если в преобразование
добавить шаблон для тега “thetag”?
< xsl:template match=”thetag">
<xsl:value-of select=”’the text’”/>
</ xsl:template>
Тогда XSL процессором будут игнорироваться все теги, кроме
тегов <thetag> (и вложенные тоже) и вместо текстового содержимого тегов
<thetag> всегда будет выводится слово “thetext”.
Итак, XSL преобразование не описывает последовательность вызовов
шаблонов, шаблоны вызываются при
просмотре входного XML файла. Шаблон в свою очередь может вызывать другие
шаблоны, тем самым последовательностью просмотра XML-файла (парсингом) мы можем
управлять из файла XSL преобразования. Любой
шаблон применяется тогда, когда встречается соответствующий тег при
просмотре (парсинге) входного XML файла. Если тег не встречается
(хотя и содержится в XML файле), то соответствующий ему шаблон не применяется. В частности, в зависимости от
содержания какого-то тега можно обрабатывать либо одни теги XML-файла, либо другие.
В XSL преобразованиях можно использовать и более
традиционный стиль программирования – так называемые именные шаблоны. Именные
шаблоны <xsl:template name=”xxx”> выполняют
роль функций, которые просто вызываются в нужном месте XSL преобразования <xsl:call-template name=”xxx”>.
7 Пример расширения преобразования
Пусть есть XML язык описания страницы и его XSL преобразование в HTML код. Мы хотим, например, добавить
какие-то новые элементы в язык описания страницы. Насколько просто это
будет сделать, то есть насколько XML-XSL технология приспособлена для таких расширений и
изменений? Эта тематика имеет много общего с расширяемостью программ, см.
М.М.Горбунов-Посадов «Расширяемые программы. Полиптих,М., 1999.
В этом и следующем параграфах приводятся
два примеры «расширяемости» XML-XSL технологии. Примеры реальные и рабочие.
В этом параграфе рассматривается пример расширения очень простого языка описания страницы, и
показывается, как меняется при этом XSL преобразование. Второй пример (в следующем параграфе) касается
построения английской версии страниц.
В параграфе 4
приводится XML описание структуры страницы. Для полного XML описания страницы необходим XML язык для описания содержания тегов
<pre>, <post> и <content>. Детально этот язык будет
описан в следующей работе, сейчас мы ограничимся его элементарным вариантом – одним тегом <info_unit>, позволяющим описать
изображение, сопутствующий изображению текст, а также ссылку. Далее этот язык расширяется и показывается, как при
этом изменяется XSL преобразование.
Вот пример описания тега <pre> с использованием info_unit
<pre>
<info_unit>
<image>image.jpg</image>
<text>
Институт образован для решения ….
</text>
<link>link.HTM</link>
</info_unit>
</pre>
Содержание <pre> - изображение, текст и ссылка.
Вот часть XSL преобразования – шаблоны для <info_unit>.
< xsl:template match="info_unit ">
<div class=”info_unit”>
< xsl:apply-templates mode="info_unit"
select="*"/>
</div>
</ xsl:template>
/* Далее следуют шаблоны для вложенных в info_unit тегов ; предполагается фиксированная
ширина изображений – 100 пикселей*/
<!--***шаблон
для изображения -->
< xsl:template mode="info_unit"
match="image">
<div
class="info_image">
<
xsl:variable
name="var_info_image" >
<
xsl:value-of
select="."/>
</
xsl:variable>
<img
src="{concat($param_base_folder,$var_info_image)}"
width="100" border="0" alt=""/>
</div>
</ xsl:template >
<!--***шаблон
для текста -->
< xsl:template mode="info_unit"
match="text">
<div
class="info_text">
<p><
xsl:value-of
select="."/>
</p>
</div>
</ xsl:template>
<!--***шаблон
для ссылки -->
< xsl:template mode="info_unit"
match="link">
<div
class="info_link">
<
xsl:variable
name="var_info_link" >
<
xsl:value-of
select="."/>
</
xsl:variable>
<a title="{$var_info_link}"
href="{$var_info_link}"
>< xsl:copy-of
select="$var_info_link"/>
</a>
</div>
</ xsl:template>
Преобразование формирует HTML теги, информация для которых берется
из описания info_unit. Если, например, тег <image> отсутствует
в теге info_unit, то преобразование просто не
сформирует тег <img>, и картинки на
странице просто не будет. Это специфика непроцедурного программирования – никаких
проверок на наличие тегов в описании
страницы мы не делаем, см. описание специфики XSL преобразования в предыдущем параграфе.
Каждый тег порождает
<div>с атрибутом class=“имя”. Это
имя определяет стиль в таблице стилей CSS.
Описание info_unit можно
разнообразить – ввести, например, автора информации (тег <author>) и заголовок (тег <title>). Например
<info_unit>
<author>xxauthorxxx</author>
<title>xxxtitlexxx</title>
<text>The
Institute was founded in …</text>
<link>link.HTM</link>
</info_unit>
А как изменится преобразование? В XSL преобразовании просто добавляются
шаблоны для новых тегов <author>
и <title>. В остальном преобразование остается без изменений.
<!--***шаблон для автора
-->
< xsl:template mode="info_unit"
match="author">
<div
class="author">
<
xsl:value-of
select="."/>
</div>
</ xsl:template>
<!--***шаблон для заголовка -->
< xsl:template mode="info_unit"
match="title">
<div
class="title">
<
xsl:value-of
select="."/>
</div>
</ xsl:template>
Конечно, нужно обеспечить, чтобы содержимое всех тегов
внутри info_unit отображалось должным образом в
окне браузера. Поэтому для имен соответствующих
<div> в CSS нужно написать стили, например такие
.author,
title{
font-style:bold;}
8 Меню и
английская версия сайта
В этом параграфе сначала
показывается, как в XML-XSL технологии
строится меню на всех страницах сайта. Далее описывается переход к английскому варианту меню и
обсуждается переход к английской версии всей страницы. В конце этого параграфа дается иллюстративный пример
применения таблиц стилей CSS для меню.
Главная страница сайта содержит меню – перечень основных
страниц сайта. Это меню обычно повторяется на
других страницах. Поэтому естественно меню расположить в отдельном XML файле. XSL преобразование берет из него
информацию и, преобразуя ее, вставляет меню в HTML страницы.
<menu>
<menu_item
link="main/history/index.htm">Страницы
истории</menu_item>
<menu_item
link="main/research/index.htm">Научные исследования
</menu_item>
<!--*** другие
пункты меню -->
</menu>
Тег menu_item содержит название элемента меню, а
атрибут link этого тега содержит адрес ссылки
(вычисляемый относительно базовой папки
сайта).
Теперь – XSL преобразование. Меню на HTML странице
будет представлено списком ссылок (<ul>…..</ul>), а вид
этого списка управляется стилями в CSS, о которых мы скажем несколько позднее.
Сначала вызов шаблона для обработки тега menu_item файла menu.xml. Наше XSL преобразование применяется к XML файлу описания страницы, а не к файлу menu.xml, поэтому мы добираемся до нужной
информации, используя функцию DOCUMENT(‘menu.xml’).
<ul>
< xsl:apply-templates mode="navigation"
select="document('menu.XML')//menu_item"/>
</ xsl:apply-templates>
</ul>
Шаблонное правило,
формирующее один пункт меню,
обрабатывает тег menu_item файла menu.xml.
< xsl:template mode="navigation" match="menu_item">
<
xsl:variable
name="var_menu_item">
<
xsl:copy-of
select="."/>
</
xsl:variable>
<li
class="navitem">
<a
title="{$ var_menu_item }"
href="(concat($param_base_folder,
@link)}">
< xsl:value-of select="$ var_menu_item "/>
</a>
</li>
</ xsl:template>
Обработка тега menu_item состоит в
следующем. Сначала содержание тега menu_item
(название пункта меню) заносится в переменную var_menu_item, а затем формируется
ссылка на языке HTML.
Значение атрибута href (ссылки) получается из пути к базовой
директории ($param_base_folder)
и пути от базовой директории в самому файлу (@link), на который указывает эта ссылка
Этот путь строится из значения атрибута link тега menu_item (это значение обозначается
как @link), текст ссылки и атрибут title берутся из переменной var_title.
Стиль меню navitem
определяется в CSS.
В конце этого параграфа после описания XSL преобразования мы вкратце остановимся на том, как работает CSS для меню.
Итак, описанное XSL преобразование на всех страницах строит основное меню,
пользуясь его XML описанием menu.xml. Если мы захотим расширить меню,
нам достаточно просто добавить в menu.xml
дополнительные теги menu_item, и
то же XSL преобразование построит новое
меню (это к вопросу о расширяемости XML-XSL технологии)
Но более интересна следующая задача – мы хотим сделать так, чтобы меню было на английском языке. В
принципе нам будут нужны целиком английские страницы для английской
версии сайта, но сначала мы ограничимся лишь меню – об английской версии всей страницы будет сказано в дальнейшем.
Итак – о меню на английском языке. Конечно, можно
сделать отдельный файл menu_english.XML, содержащий английское меню (перевести только названия и
изменить значения LINK). То же XSL преобразование, но с document(‘menu_еnglish.xml’), сделает английское меню на странице. Но естественно русское и английское меню хранить
в одном файле – меняя одно, мы тут же можем корректировать и другое (по крайней мере мы не забудем об английском варианте меню). В
этом случае в файл menu.XML просто вводим теги menu_item_engl, куда и записываем английские варианты названия страниц (теги естественно располагать парами –
русский-английский menu_item).
Теперь файл menu.xml выглядит так
<menu>
<menu_item
link="main/history/index.htm">Страницы истории
</menu_item>
<menu_item_engl link="main/history/
index_engl.htm ">History
</menu_item_engl>
<!--***другие
пункты меню -->
</menu>
А как измениться само
преобразование? Оно меняется минимально
– в случае разных языков мы просто обрабатываем разные теги. В русском случае
преобразование обрабатывает теги menu_item, в английском - menu_item_engl (переменная var_language, определяемая в самом начале
преобразования, указывает на язык данной
страницы).
<ul>
<
xsl:if
test="$var_language='russian'">
<
xsl:apply-templates
mode="navigation"
select="document('menu.XML')//menu_item"/>
</ xsl:if>
<
xsl:if
test="$var_language='english'">
<
xsl:apply-templates
mode="navigation"
select="document('menu.XML')//menu_item_engl"/>
</ xsl:if>
</ul>
Шаблон для пункта меню остается абсолютно таким же, меняется лишь заголовок
шаблона – шаблон обрабатывает
теперь не только тег <menu_item>, но и <menu_item_engl>. Кстати, обработку
<menu_item_engl> можно сделать и
в отдельном файле и присоединить его с помощью include.
< xsl:template mode="navigation" match="menu_item |
menu_item_engl">
<
xsl:variable
name="var_title">
<
xsl:copy-of
select="."/>
</
xsl:variable>
<li
id="navitem">
<a
title="{$var_title}"
href="{concat($param_base_folder,
@link)}">
< xsl:value-of select="$var_title"/>
</a>
</li>
</
xsl:template>
Такой же прием можно применить и для других «общих» файлов (файлов, хранящих
информацию, используемую на разных страницах сайта) – для файла новостей news_list и для файла публикаций publication_list.
Теперь об английском варианте всего сайта.
Английская версия сайта
может содержать не все аналоги страниц русского сайта. К тому же содержание
некоторых английских страниц может быть
несколько другое, чем русских. Например, некоторые страницы со статичной
информацией могут быть слиты в одну, информация из потока новостей может не отображаться на некоторых английских
страницах, и т.д.
Описания (на
специальном XML языке) для русской и английской страниц будут храниться в разных файлах. В принципе эти описания можно было бы хранить в одном файле (так, как
это делалось в файле menu.xml), дублируя теги их английскими вариантами и переводя
их содержимое на английский язык. Но
содержание русской и английской страниц может быть очень разным, содержание
тегов довольно большим (если на странице большие тексты), поэтому русский и
английский варианты страницы разнесены.
Структура описания русской и английской страниц совершенно
одинакова – те же теги и атрибуты, только с разным (английским или русским) наполнением.
Английскую версию страницы мы получаем, применяя то же XSL преобразование, но к описанию
английской страницы. В начальном теге
<page> описания страницы есть
атрибут language, определяющий язык данной страницы. В самом начале XSL преобразования этот атрибут
записывается в переменную var_language.
Резюме – английский вариант страницы
В общем случае для получения
английской версии страницы нужно сделать
следующее
1 сформировать XML описание английского варианта
страницы (в абсолютно том же формате, что и описание русского варианта)
2 во всех XML файлах с дополнительной информацией
о русской странице мы добавляем аналогичные теги для английской страницы (как в
файле menu.xml)
3
Вызовы
шаблонов <XSL:call-templates select=”tag”/>, которые обращаются к XML файлам с дополнительной информацией
о странице (а не к самому файлу описания страницы), заменяются вызовами <XSL:call-templates select=”tag_engl”/>“. Точнее в зависимости от
языка страницы вызывается то одни, то другие шаблоны. Само содержание русских и
английских шаблонов совершенно одинаково (результат разный потому, что они
обрабатывают разные теги)
Напомним основное положение – само XML описание страницы для русского и
английского варианта абсолютно идентично по структуре (те же теги и те же
атрибуты, только разное наполнение)
Замечание – CSS для
меню
Совсем кратко на
рассмотренном примере меню покажем, как работает CSS. Выше
описывалось XSL
преобразование, генерирующее меню на HTML странице.
Код после преобразования такой
<ul>
<li class="navitem">
<a title="
menu_item_name” href="адрес">ПУНКТ
МЕНЮ </a>
</li>
<!-- ***другие пункты меню -->
</ul>
Стиль "navitem"
в CSS определяет
стиль для элементов меню. Например, зададим величину букв и их цвет
.navitem {
display:
block;
font-size:
13px;
color: #900;}
Если мы не будем задавать стиль для navitem, то
величина букв и их цвет берется из стиля тегов, в которые вложен тег
<li> (или это можно определить в стиле для тега <a>). Далее можно определить стиль ссылок. Например, ссылки не будут
подчеркиваться (text-decoration: none), если в CSS
есть такой стиль
a:link
{
text-decoration:
none;}
А если и этот
стиль не определен, то вид ссылок
диктуется просто правилами HTML по умолчанию, т.е. ссылки будут
подчеркиваться . Будет ли каждый элемент списка ссылок отмечен точкой (таков стиль списка в HTML по умолчанию) в свою очередь
зависит от того, задаем ли мы в CSS специально стиль для тега <ul>. Точек не будет, если в CSS
содержится стиль
ul {
list-style:
none;
}
Конечно в одних местах страницы стиль тега <ul> может быть одним, в других
местах – другим. В параграфе 2 мы говорили о том, как это достигается –
некоторые теги <ul> могут иметь имена (class или id) и соответственно свои собственные
стили в таблице стилей CSS.
9 Схема
преобразования описания страницы
Выше мы говорили о некоторых частях XSL преобразования, переводящего XML описание страницы в HTML код. В предыдущем параграфе обсуждалось
построение меню и его английского варианта, ранее мы говорили о совсем
элементарном – модельном – XML языке описания содержания страницы
и о расширении этого языка. В этом параграфе эскизно описывается схема XSL преобразования всего XML описания страницы.
Напомним схему XML описания страницы (см параграф 5).
<page path="main/"
language="russian"
translation=’english’ news_channels="main, publication">
<header
type=”xx”/>
<navigation/>
<content>
<!--**Информация
зависит от того, новостная страница или нет-->
</content>
<footer/>
<local_css>????
</local_css>
</page>
Для новостной страницы
содержание тега <content> такое
<content>
<pre>
/*Здесь помещается
информация перед новостями*/
</pre>
<news/>
<post>
<!--***Здесь
помещается информация после новостей-->
</post>
</content>
Для страницы без новостей тег <content> содержит конкретное описание содержания.
Разработка XML языка описания такого содержания – это тема следующей работы. Назовем такой язык CONTENT LANGUAGE.
На этом языке
описывается содержимое тегов <content> в случае страницы без новостей,
и тегов <pre> и <post> в случае новостной страницы. Содержимое тега <news> – а это описание новостей на
странице – берется из файла news_list. Язык описания новостей NEWS LANGUAGE – тоже предмет дальнейшей
разработки. Тег info_unit, о котором говорилось в параграфе 7, можно считать
простейшим вариантом упомянутых языков. Возможно, что язык описания новостей –
это просто часть языка CONTENT LANGUAGE.
Мы считаем, что все шаблоны для CONTENT LANGUAGE
и для языка описания новостей написаны в отдельных файлах content_language.xsl
и news_language.xsl . Эти файлы присоединяются к основному преобразованию через
include. Эти шаблоны имеют атрибут mode=” content_language” и
mode=”news_language” соответственно.
Это сделано для того,
чтобы разделять шаблоны, отвечающие за различные части XSL преобразования.
Итак, схематически опишем, как работает XSL преобразование XML описания страницы.
Сначала определяем
параметры – некоторые величины, которые
постоянны для всех страниц сайта. В частности такие, как максимальное
количество новостей, показываемых на странице, путь до базовой директории и др.
Эти параметры хранятся в файле CONFIGSYS.xml , параметры из
этого файла извлекает преобразование CONFIGSYS.xsl, которое присоединяем к основному
преобразованию через include.
<xsl:include href=" CONFIGSYS.xsl "/>
Далее определяются
переменные, которые будут использоваться в преобразовании – язык страницы,
перечисление всех тех каналов, новости из которых попадают на эту страницу, и
пр.
<xsl:variable
name="var_language">
<xsl:value-of
select="page/@language"/>
</xsl:variable>
<xsl:variable
name="var_translation">
<xsl:value-of
select="page/@translation"/>
</xsl:variable>
<xsl:variable
name="var_page_channels">
<xsl:value-of
select="page/@channels"/>
</xsl:variable>
<!--***другие переменные -->
Далее идет блок
переменных – имен внешних файлов, данные из которых используются в преобразовании.
<xsl:variable name="var_news_list">
<xsl:value-of
select="’news_list.xml’"/>
</xsl:variable>
<!--***другие
внешние файлы-->
Этот блок переменных играет
важную роль в отладочном режиме при предварительном просмотре страниц сайта.
Имена отладочных – измененных – файлов подставляются в этот блок перед
применением XSL
преобразования. Подробнее см. параграф 10.
Далее идет обработка
тегов <header>
и <menu> –
подключение (include)
отдельных XSL
файлов
<xsl:include
href="header.xsl"/>
<xsl:include
href="menu.xsl"/>
О построении меню
было рассказано в параграфе 8.
Теперь об обработка заголовка страницы (тега <header>).
Мы уже упоминали, что не имеет особого смысла описывать
содержание этого тега в XML виде. Такой вид удобен для внесения изменений, а в
заголовок изменения в принципе не должны вносится. Заголовок есть единое целое.
При изменении, например, какой то части
текста заголовка, изменения должны будут
коснуться и других частей заголовка. Причина этого в том, что графика в
заголовке – в частности логотип – влияет на то место, куда должен быть помещен
текст заголовка, и наоборот, текст заголовка влияет на графику, на ее место, на
размер. Заголовок – это композиция, которая делается с учетом всех элементов, в
заголовок входящих. В параграфе 4 уже упоминалось, что надписи в заголовке
должны быть текстовыми, а не представлены в виде изображений.
Поэтому часть XSL преобразования, отвечающее за заголовок, будет в основном
состоять из HTML кода заголовка. Но только в основном, там будет и некоторая «логика». Страницы могут
иметь несколько типов заголовков. Заголовок основной страницы может отличаться
от заголовков других страниц, например, графикой. В заголовок страницы мы помещаем разные ссылки (сервисы
страницы, см. параграф 4 ) – ссылки на RSS нашего сайта, на перевод текущей страницы, на страницу поиска
и подписку на новости текущей страницы
(если страница новостная). На конкретной странице некоторые ссылки могут
отсутствовать.
Поэтому в XSL преобразовании, отвечающим за
заголовок, встречаются операторы языка XSL, выбирающие нужный тип заголовка
или нужную ссылку. Это XSL преобразование находится в отдельном файле header.xsl, который подсоединяетсяк общему
преобразованию через include.
Какая информация должна передаваться XSL преобразованию заголовка? Тип заголовка - указывается в теге заголовка
<header type=”xx” text=”xxx”>. Заголовки могут быть нескольких типов - заголовок первой – основной – страницы сайта,
заголовки страниц, на которые ссылается
главное меню, и заголовки
информационных страниц сайта. Заголовки
отличаются графикой и текстовыми надписями. В заголовке ссылка на RSS всегда присутствует, наличие
перевода определяется атрибутом translation
тега <page>, поиск по сайту присутствует всегда, подписка на
новости – только для новостных страниц (наличие атрибута channel тега <page>).
Теперь переходим к содержанию самой страницы. Начинаем с
обработки тега <content>.
<xsl:call-templates select=”//content”/>
Шаблон для тега <content>
<xsl:template
match=”//content”>
<div id=”content”>
(A) <xsl:call-templates
mode=”content_language” select=”//content/*”/>
</div>
</xsl:template>
Сначала шаблон для <content> образует <div id=”content”> и вызываются
шаблоны с
mode=”content_language” для тегов, вложенных
в тег <content>. Если рассматривается не новостная страница, то в <content> вложены только теги языка CONTENT LANGUAGE, и для них есть соответствующие шаблоны с тем же
значением атрибута mode=”content_language”. Эти шаблоны и будут выполняться.
Для новостной страницы вызов шаблонов (A) игнорируется – непосредственно в
<content> вложены теги<pre>,<news> и <post>, для них шаблонов с атрибутом mode=”content_language”
нет.
Теперь тег <pre> и соответствующий шаблон
(B) <xsl:call-templates
select=”//content/pre”/>
<xsl:template match=”pre”>
<div id=”pre”>
<xsl:call-templates
mode=”content_language” select=”//pre/*”/>
</div>
</xsl:template>
Вызов (B) работает только для новостной страницы, и шаблон <xsl:template match=”pre”> обрабатывает
содержание тега <pre>. Причем
опять для тегов, вложенных в <pre>
вызываются шаблоны с mode=”content_language”.
Теперь тег <news>
(C) <xsl:call-templates select=”//content/news”/>
<xsl:template match=”news”>
<div id=”news”>
<!--***обработка новостей c атрибутом mode=”news_language”-->
</div>
</xsl:template>
Вызов (C) тоже работает
только для новостной страницы, и шаблон <xsl:template match=”news”> занимается обработкой
новостей. Новости берутся из файлов news_list и publication_list. Здесь эту обработку мы не детализируем.
И, наконец, тег <post>.
(D) <xsl:call-templates
select=”//content/post”/>
<xsl:template match=”post”>
<div id=”post”>
<xsl:call-templates
mode=”content_language” select=”//post/*”/>
</div>
</xsl:template>
Вызов (D) тоже работает
только для новостной страницы – обрабатывается содержание тега <post> (аналогично тегу <pre>)
После <content> обрабатывается тег <footer/> –
вставляется COPYRIGHT.
К преобразованию присоединяются шаблоны для языков CONTENT LANGUAGE и NEWS LANGUAGE.
<xsl:include href="
content_language.xsl
"/>
<xsl:include href="
news_language.xsl
"/>
Если в XML описании страницы есть тег <local_css>,
то в начале преобразования надо образовать HTML тег <style type="text/css" …> и туда вставить
содержимое тега <local_css>.
10 Редакторский и
отладочный режимы
Предполагается,
что XSL преобразование
происходит «на лету», т е. при вызовах внутренних XML страниц сайта (вызовы типа
<a href=”page.xml>) сначала
к XML страницам применяется XSL преобразование, а затем результат
посылается пользователю.
Для нормальной
работы новостного сайта, конечно, должны быть предусмотрены средства, автоматизирующие
редактирование новостной ленты и также
ленты публикаций.
Примерная схема
редактирования новостей (и публикаций) такова. Вызывается редакторский модуль,
в нем можно выбрать уже существующую новость
и ее редактировать, можно менять ее атрибуты. Например, можно сделать новость невидимой пользователю, поставив
атрибут «не публиковать». Можно вызвать форму для новости, заполнить ее и
отослать на сервер, где новость поместиться в XML файл новостей. Но она не будет
видна пользователям, так как при вводе имеет атрибут «не публиковать».
Из
редакторского модуля мы можем посмотреть сайт в специальном редакторском
режиме. Этот режим отличается от стандартного лишь тем, что на страницах сайта
видны все новости и публикации, даже с атрибутом «не публиковать». Тем самым
редактор может посмотреть, как выглядит результат редактирования. Убедившись в
правильности, он меняет атрибут «не
публиковать» на «публиковать». Показать страницу в редакторском режиме можно,
сделав небольшое изменение в XSL преобразовании
(убрав проверку значения соответствующего атрибута).
Но кроме
«штатных» ситуаций внесения новостей и публикаций иногда может потребоваться добавление новых
страниц или внесение изменений в
содержание старых. В этом случае мы должны редактировать другие XML файлы, а не
только файлы новостей или публикаций. Эти изменения не должны сразу отражаться на виде сайта в интернете. Вносимые изменения – это
рабочие изменения, еще нужно проверить их правильность. Для этого существует
отладочный режим.
Изменяя какой-нибудь XML файл file.xml, мы записываем
его отладочную версию file_debug.xml в ту же директорию, в которой находится файл file.xml.
От чего зависит результат XSL преобразования XML файла
страницы? Во-первых, от самого XML файла
страницы, и, во-вторых, от других
файлов, из которых мы берем информацию, помещаемую на странице.
Например, содержание стрканицы может зависеть от файла publication_list.xml, к содержанию
которого мы добираемся через функцию “document” (см. параграф
8). Таких файлов всего несколько (файлы меню, новостей, публикаций…),
назовем их «внешними». В отладочном режиме при применении XSL преобразования
к файлу страницы надо подключать уже
измененные «внешние» файлы (если они были изменены).
Итак, пусть мы
сделали некоторые изменения в XML файлах file.xml, может быть в
нескольких файлах сразу, и записали
эти файлы под названиями file_debug.xml. Файлы file.xml остались
прежними и пользователи в интернете видят не измененные страницы сайта. Теперь мы
хотим посмотреть, как выглядят страницы сайта при сделанных изменениях
Вызываем,
например, главную страницу сайта в
отладочном режиме, т.е. вызов выглядит так main.xml?debug. Серверная программа, обнаружив
слово debug, перехватывает вызов. Во-первых, она смотрит,
есть ли файл main_debug.xml. Если есть, то
будет обрабатываться этот файл – XSL преобразование будет применяться к main_debug.xml. Если файла main_debug.xml нет, то преобразование применяется к файлу main.xml.
Теперь само
преобразование. Быть может, изменен
«внешний» файл, от которого зависит результат преобразования. Поэтому
серверная программа проверяет среди всех «внешних» файлов, произошли ли в них изменения (есть ли
файлы file_debug.xml). В начале XSL преобразования
есть блок переменных, которым присваиваются имена всех «внешних» файлов. Серверная
программа немного корректирует этот блок, все «внешние» измененные файлы file.xml заменяя
на file_debug.xml. Далее применяется
XSL преобразование
и получается страница main в тестовом режиме. Этого же можно добиться по-другому, передавая имена внешних файлов как параметры в XSL преобразование
из среды сервера.
Но есть еще
одна маленькая деталь – мы находимся в отладочном режиме и хотели бы в этом
режиме и оставаться. То есть мы хотели бы по внутренней ссылке на полученной странице не выходить из отладочного режима. Отладочный режим – это
вызов вида page.xml?debug. Поэтому после
XSL преобразования
мы запускаем очень простую процедуру над
HTML файлом – все
ссылки типа <a href=”file.xml> заменяются на
<a href=”file.xml?debug>. Полученная
в результате таких преобразований HTML страница возвращается как тестовая. Теперь по
внутренним ссылкам с этой страницы мы опять попадаем в отладочный режим.
Вот и все про
отладочный режим. Конечно, мы из него можем выйти, если уйдем по ссылке на
страницу не внутреннюю (так как тогда ссылка будет на .htm файл, а не на .xml файл). В
обычном, не отладочном режиме, страницы сайта продолжают оставаться без
изменений.
После того, как
мы протестировали страницы сайта в отладочном режиме и остались довольны
результатом, можно внести окончательные изменения на сайт – все файлы file_debug.xml
переименовать в file.xml (записать поверх старых).
Итак, сайт
может работать в трех режимах. Режим пользователя – как пользователь видит сайт в интернете. Режим редактора – им
пользуется редактор для предварительного просмотра вводимых им новостей и
публикаций. И режим отладки – им пользуется администратор сайта для проверки
сделанных им изменений в XML файлах системы.
11 Заключение
В работе приведены
самые общие принципы использования XML-XSL технологии для автоматического создания
интернет страниц по их XML описанию.
Приводятся несколько конкретных примеров использования этих принципов. В
дальнейшем предполагается более детальное обсуждение языка описания страниц и других составных частей этой технологии. В
частности здесь мы не касались
программной поддержки этой технологии.
Используя эту технологию, для изменения содержания страницы
мы вносим изменения в содержание соответствующих тегов в XML описании страницы, что
автоматически отражается на представлении страницы в браузере. Внесение
новостей на страницу тоже состоит в редактировании (дополнении) XML файла новостей.
Дополнение (расширение) содержания страницы происходит за счет дополнения XML описания страницы, расширения XSL преобразования и дополнения в
таблице стилей CSS.
Поясним сказанное – в чем заключается, например, введение
новых элементов страницы? Во-первых, в описании страницы появятся новые теги
для этих новых элементов (расширяется язык описания страницы). Во-вторых, в XSL преобразовании появятся новые
шаблоны для этих тегов. И в-третьих, в
таблице стилей CSS появляются новые стили, говорящие, как выглядят эти новые
элементы. Конечно, в общем случае может потребоваться скорректировать ранее
написанные части XSL преобразования и ранее написанные стили – если изменения кардинальны.
Другая ситуация: мы хотим сделать из одноколоночного
дизайна двухколоночный дизайн. Тогда в
описании страницы разумно ввести два тега <first_column>, <second_column>
и по ним разнести нужную информацию – раньше все элементы страницы шли
одним общим списком , теперь мы должны их как то разделить по колонкам. Конечно, лучше иметь мнемонические названия тегов, например,
<letters> вместо <first_column>, если все письма собираются в
первую колонку.
Далее XSL преобразование формирует теги <div id=”first_column”> и<div
id=”second_column”> со всем их содержимым. И теперь в
CSS описываются стили для
#first_column и #second_column. И в принципе все.
Конечно, может потребоваться скорректировать некоторые стили элементов внутри
колонок. Например, когда стили этих
элементов задают фиксированную их
ширину, и из-за этого они просто не могут поместиться в новую ширину
колонки.
В принципе двухколоночный дизайн можно сделать, и не меняя XML описания, а сгруппировав нужные
элементы страницы с помощью XSL преобразования.