Ордена Ленина ИНСТИТУТ ПРИКЛАДНОЙ МАТЕМАТИКИ имени М.В.Келдыша Российской академии наук Будинас Б.Л. XML-XSL технология для построения интернет сайта Часть 2 : XSL преобразования Москва 2006 г. 2 УДК 519.68 Б.Л.Будинас. XML-XSL технология для построения интернет сайта. Часть2: XSL преобразования Описываются принципы использования XML-XSL технологии для построения интернет-сайта, ориентированного на небольшой поток новостей. Обсуждается структура такого сайта. Рассматривается роль составных частей этой технологии – таблицы стилей CSS, XML описания страницы и XSL преобразования. Ключевые слова: интернет, сайт, описание содержания страницы, XML, СSS, XSL преобразование B.L.Budinas. XML-XSL technology for internet site development. Part 2: XSL transformations Principles of XML-XSL technology application for news-oriented internet site development are discussed. The role of different parts of this technology – CSS, XML description of page content, XSL transformation – is considered. Key words and phrases: internet, site, page description language, XML, CSS, XSL transformation. 3 Содержание 6 Специфика XSL преобразований…………………. 4 7 Пример расширения XSL преобразования……... 8 Меню и английская версия сайта…………………. 11 9 Схема преобразования описания страницы…… 16 10 Редакторский и отладочный режимы…………..... 21 11 Заключение…………………………………………… 23 8 4 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 tem- 5 plate 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> 6 fff </tag1> <tag3>ddd</tag3> <tag2>ccc</tag2> </file> будет последовательность aaabbbcccfffdddccc. Но XSL-преобразование может нию действия XSL процессора. переопределить совершаемые по умолча- Такие переопределения называются шаблонами и записываются как <xsl:template match=”xxx”>ТЕЛО ШАБЛОНА</ xsl:template>. Шаблон может записывать что-то в выходной файл. Кроме этого он определяет порядок дальнейшего просмотра вложенных тегов. Например, вызов <xsl:calltemplates 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> 7 Это преобразование опять записывает в выходной 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 файле), то соответствую- 8 щий ему шаблон не применяется. В частности, в зависимости от содержания какого-то тега можно обрабатывать либо одни теги XML-файла, либо другие. В XSL преобразованиях можно использовать и более традиционный стиль программирования – так называемые именные шаблоны. Именные шаблоны <xsl:template name=”xxx”> выполняют роль функций, которые просто вызываются в нужном месте XSL преобразования <xsl:call-template name=”xxx”>. 7 Пример расширения преобразования Пусть есть XML язык описания страницы и его XSL преобразование в HTML код. Мы хотим, например, добавить какие-то новые элементы в язык описания страницы. Насколько просто это будет сделать, то есть насколько XMLXSL технология приспособлена для таких расширений и изменений? Эта тематика имеет много общего с расширяемостью программ, см. М.М.ГорбуновПосадов «Расширяемые программы. Полиптих,М., 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> Институт образован для решения …. 9 </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> 10 Преобразование формирует 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;} 11 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="."/> 12 </ 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 выглядит так 13 <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> 14 Такой же прием можно применить и для других «общих» файлов (файлов, хранящих информацию, используемую на разных страницах сайта) – для файла новостей news_list и для файла публикаций publication_list. Теперь об английском варианте всего сайта. Английская версия сайта может содержать не все аналоги страниц русского сайта. К тому же содержание некоторых английских страниц может быть несколько другое, чем русских. Например, некоторые страницы со статичной информацией могут быть слиты в одну, информация из потока новостей может не отображаться на некоторых английских страницах, и т.д. Описания (на специальном XML языке) для русской и английской страниц будут храниться в разных файлах. В принципе эти описания можно было бы хранить в одном файле (так, как это делалось в файле menu.xml), дублируя теги их английскими вариантами и переводя их содержимое на английский язык. Но содержание русской и английской страниц может быть очень разным, содержание тегов довольно большим (если на странице большие тексты), поэтому русский и английский варианты страницы разнесены. Структура описания русской и английской страниц совершенно одинакова – те же теги и атрибуты, только с разным (английским или русским) наполнением. Английскую версию страницы мы получаем, применяя то же XSL преобразование, но к описанию английской страницы. В начальном теге <page> описания страницы есть атрибут language, определяющий язык данной страницы. В самом начале XSL преобразования этот атрибут записывается в переменную var_language. Резюме – английский вариант страницы В общем случае для получения английской версии страницы нужно сделать следующее сформировать XML описание английского варианта страницы (в абсолютно том же формате, что и описание русского варианта) 2 во всех XML файлах с дополнительной информацией о русской странице мы добавляем аналогичные теги для английской страницы (как в файле menu.xml) 3 Вызовы шаблонов <XSL:call-templates select=”tag”/>, которые обращаются к XML файлам с дополнительной информацией о странице (а не к самому файлу описания страницы), заменяются вызовами <XSL:call-templates select=”tag_engl”/>“. Точнее в зависимости от языка страницы вызывается то одни, то другие шаблоны. Само со1 15 держание русских и английских шаблонов совершенно одинаково (результат разный потому, что они обрабатывают разные теги) Напомним основное положение – само 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; } 16 Конечно в одних местах страницы стиль тега <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. На этом 17 языке описывается содержимое тегов <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> <!--***другие переменные --> 18 Далее идет блок переменных – имен внешних файлов, данные из которых используются в преобразовании. <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 нашего сайта, на перевод текущей страницы, на страницу поиска и подписку на новости текущей 19 страницы (если страница новостная). На конкретной странице некоторые ссылки могут отсутствовать. Поэтому в XSL преобразовании, отвечающим за заголовок, встречаются операторы языка XSL, выбирающие нужный тип заголовка или нужную ссылку. Это XSL преобразование находится в отдельном файле header.xsl, который подсоединяетсяк общему преобразованию через include. Какая информация должна передаваться XSL преобразованию заголовка? Тип заголовка - указывается в теге заголовка <header type=”xx” text=”xxx”>. Заголовки могут быть нескольких типов - заголовок первой – основной – страницы сайта, заголовки страниц, на которые ссылается главное меню, и заголовки информационных страниц сайта. Заголовки отличаются графикой и текстовыми надписями. В заголовке ссылка на RSS всегда присутствует, наличие перевода определяется атрибутом translation тега <page>, поиск по сайту присутствует всегда, подписка на новости – только для новостных страниц (наличие атрибута channel тега <page>). Теперь переходим к содержанию самой страницы. Начинаем с обработки тега <content>. <xsl:call-templates select=”//content”/> Шаблон для тега <content> (A) <xsl:template match=”//content”> <div id=”content”> <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”/> 20 <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 "/> 21 <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 файлы, а не только файлы новостей или публикаций. Эти изменения не должны сразу отражаться на виде сайта в интернете. Вносимые изменения – это рабочие изменения, еще нужно проверить их правильность. Для этого существует отладочный режим. 22 Изменяя какой-нибудь 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 страница возвращается как 23 тестовая. Теперь по внутренним ссылкам с этой страницы мы опять попадаем в отладочный режим. Вот и все про отладочный режим. Конечно, мы из него можем выйти, если уйдем по ссылке на страницу не внутреннюю (так как тогда ссылка будет на .htm файл, а не на .xml файл). В обычном, не отладочном режиме, страницы сайта продолжают оставаться без изменений. После того, как мы протестировали страницы сайта в отладочном режиме и остались довольны результатом, можно внести окончательные изменения на сайт – все файлы file_debug.xml переименовать в file.xml (записать поверх старых). Итак, сайт может работать в трех режимах. Режим пользователя – как пользователь видит сайт в интернете. Режим редактора – им пользуется редактор для предварительного просмотра вводимых им новостей и публикаций. И режим отладки – им пользуется администратор сайта для проверки сделанных им изменений в XML файлах системы. 11 Заключение В работе приведены самые общие принципы использования XML-XSL технологии для автоматического создания интернет страниц по их XML описанию. Приводятся несколько конкретных примеров использования этих принципов. В дальнейшем предполагается более детальное обсуждение языка описания страниц и других составных частей этой технологии. В частности здесь мы не касались программной поддержки этой технологии. Используя эту технологию, для изменения содержания страницы мы вносим изменения в содержание соответствующих тегов в XML описании страницы, что автоматически отражается на представлении страницы в браузере. Внесение новостей на страницу тоже состоит в редактировании (дополнении) XML файла новостей. Дополнение (расширение) содержания страницы происходит за счет дополнения XML описания страницы, расширения XSL преобразования и дополнения в таблице стилей CSS. Поясним сказанное – в чем заключается, например, введение новых элементов страницы? Во-первых, в описании страницы появятся новые теги для этих новых элементов (расширяется язык описания страницы). Во-вторых, в XSL преобразовании появятся новые шаблоны для этих тегов. И в-третьих, в таблице стилей CSS появляются новые стили, говорящие, как выглядят эти 24 новые элементы. Конечно, в общем случае может потребоваться скорректировать ранее написанные части XSL преобразования и ранее написанные стили – если изменения кардинальны. Другая ситуация: мы хотим сделать из одноколоночного дизайна двухколоночный дизайн. Тогда в описании страницы разумно ввести два тега <first_column>, <second_column> и по ним разнести нужную информацию – раньше все элементы страницы шли одним общим списком , теперь мы должны их как то разделить по колонкам. Конечно, лучше иметь мнемонические названия тегов, например, <letters> вместо <first_column>, если все письма собираются в первую колонку. Далее XSL преобразование формирует теги <div id=”first_column”> и<div id=”second_column”> со всем их содержимым. И теперь в CSS описываются стили для #first_column и #second_column. И в принципе все. Конечно, может потребоваться скорректировать некоторые стили элементов внутри колонок. Например, когда стили этих элементов задают фиксированную их ширину, и из-за этого они просто не могут поместиться в новую ширину колонки. В принципе двухколоночный дизайн можно сделать, и не меняя XML описания, а сгруппировав нужные элементы страницы с помощью XSL преобразования.