Использование XSLT в качестве таблицы стилей для HTML

Как следует из названия, Extensible Stylesheet Language Transformations (XSLT) можно использовать в качестве таблицы стилей. Аналогично Cascading Style Sheets (CSS), XSLT помогает отделить стиль от содержимого. При помощи XSLT можно упростить и улучшить XHTML-документы, а также облегчить навигацию. В данной статье рассматривается использование XSLT в качестве таблиц стилей, которые могут работать на сервере или в любом современном интернет-браузере. Основы разработки XSLT-таблиц стилей иллюстрируются примерами.

Юрген M. Регель, старший инженер-программист, TUI InfoTec GmbH

Юрген Регель (Jürgen M. Regel) работает старшим инженером-программистом в подразделении Architecture Management & Software Engineering компании TUI InfoTec GmbH, Ганновер, Германия. Основное внимание уделяет интеграции корпоративных приложений в индустрии туризма.



29.06.2012

Введение

Когда вы слышите словосочетание "таблица стилей", вы, вероятно, сразу представляете себе CSS-таблицы стилей. XSLT-таблицы стилей обычно используются для XML-преобразований, таких как отображение данных между Web-сервисами. Поскольку XSLT отлично подходит для этих целей, был создан псевдоним <xsl:transform> элемента верхнего уровня <stylesheet>, хотя он редко используется. Входная структура такого XSLT-преобразования совершенно отличается от выходной. Отличаются даже пространства имен.

Напротив, входная структура XSLT-таблицы аналогична выходной структуре, но проще. Некоторые теги расширяются, но большинство просто копируется без изменений. Входные и выходные пространства имен одинаковы (HTML). Входной документ может также содержать директивы для таблицы стилей (например, создать сноску), которые принадлежат другому пространству имен и не участвуют в выходе.

Часто используемые сокращения

  • CSS: Cascading Style Sheets (каскадные таблицы стилей)
  • XHTML: Extensible Hypertext Markup Language (расширяемый язык разметки гипертекста)
  • XPath: XML Path Language (язык запросов к элементам XML-документа)
  • XSLT: Extensible Stylesheet Language Transformations (расширяемый язык преобразований таблиц стилей)

В данной статье рассматривается использование XSLT для обогащения XHTML-документов. Примеры, приведенные в статье, демонстрируют, как использовать директивы, как ссылаться на фрагменты других исходных документов, как перемещаться по главному документу, используя ссылки. Также анализируются различия между интерпретацией и компиляцией страниц.

Ограничения CSS-таблиц стилей

XSLT-таблица стилей не запрещает использовать другие технологии, такие как JavaScript или CSS. CSS подходят для изменения шрифтов, выделения текста, изменения цвета, отступов и т.д. Они не годятся для комбинирования информации из разных источников, например, для создания сносок, модулей или для генерирования оглавлений. Здесь на передний план выходит технология XSLT, дополняющая, но не заменяющая CSS.


Примеры, демонстрирующие возможности XSLT

На практике вы можете собрать весь XSLT-код в один файл. В этой же статье для простоты каждый пример находится в отдельном XSLT-файле, за исключением некоторого кода, который необходим постоянно. В листинге 1 приведен необходимый исходный код.

Листинг 1. Необходимый код (в samples/common.xml)
<s:stylesheet
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://www.w3.org/1999/xhtml"
	xmlns:a="http://sourceforge.net/projects/arbalo/"
	xmlns:s="http://www.w3.org/1999/XSL/Transform"
	exclude-result-prefixes="a h"
	version="1.0"
>
	<s:template match="h:head">
		<s:copy>
			<s:apply-templates select="@*|node()"/>
			<meta
				http-equiv="content-type"
				content="text/html;charset=UTF-8" />
			<link
				href="common.css"
				rel="stylesheet"
				type="text/css" />
		</s:copy>
	</s:template>
	
	<s:template match="*">
		<s:copy>
			<s:copy-of select="@*"/>
			<s:apply-templates/>
		</s:copy>
	</s:template>
</s:stylesheet>

Пространство имен для XHTML определяется дважды: по умолчанию и h:. Пространство имен по умолчанию используется для написания выходных XHTML-тегов, когда префикса пространства имен следует избегать. h: используется в XPath-выражениях.

В данной статье используется XSLT версии 1.0. В настоящее время большинство браузеров не может интерпретировать XSLT 2.0. Однако можно выполнять XSLT на сервере. XSLT 2.0 также предоставляет следующие возможности:

  • XPATH 2.0 (if...then...else и много встроенных функций);
  • встроенные и созданные пользователем XPATH-функции;
  • группировку.

В листинге 1:

  • s:template match="head" расширяет раздел head исходного документа, добавляя ссылку на CSS-таблицу стилей. Даже если кодировкой по умолчанию в XML является UTF-8, некоторым браузерам для ее визуализации необходим тип содержимого.
  • s:template match="*" - полная копия по умолчанию. В принципе в целевой документ копируется все. Если бы этот шаблон отсутствовал, в целевой документ копировалось бы только текстовое содержимое тегов. Узлы инструкций по обработке не копируются.

Все другие примеры, используемые в данной статье, - это отдельные файлы, импортирующие common.xsl.

Обогащение

Обогащение (enrichment) - это добавление новой функциональности, не запрашиваемой явно в исходном документе. Примером может служить ссылка на CSS-таблицу стилей в листинге 1. Попробуйте еще один пример - добавьте к каждой внутренней ссылке маленькую стрелку (^ v) указывающую, находится ли цель до или после нее. В листинге 2 приведена таблица стилей.

Листинг 2. Таблица стилей (в samples/linkUpDown.xsl)
<s:stylesheet
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://www.w3.org/1999/xhtml"
	xmlns:s="http://www.w3.org/1999/XSL/Transform"
	version="1.0"
>
	<s:import href="common.xsl"/>
	<s:template match="h:a[starts-with(@href,'#')]">
		<s:copy>
			<s:copy-of select="@*"/>
			<s:variable name="name" select="substring-after(@href,'#')"/>
			<s:choose>
				<s:when test="preceding::h:a[@name=$name]">
					<s:text>^</s:text>
				</s:when>
				<s:when test="following::h:a[@name=$name]">
					<s:text>v</s:text>
				</s:when>
			</s:choose>
			<s:apply-templates/>
		</s:copy>
	</s:template>
</s:stylesheet>

Прежде всего в листинге 2 импортируется общая таблица стилей. Внутренние ссылки ищутся по шаблону (начинаются с '#'). Если закладка, на которую указывает ссылка, предшествует ссылке, добавляется стрелка вверх, в противном случае - стрелка вниз

s:copy-of и s:apply-templates гарантируют, что ничего не будет пропущено.

В листинге 3 приведен пример документа с внутренними ссылками, обогащенного при помощи таблицы стилей из листинга 2.

Листинг 3. Исходный документ (в samples/linkUpDown.xml)
 <?xml-stylesheet href="linkUpDown.xsl" type="text/xsl"?>
 <html xmlns="http://www.w3.org/1999/xhtml">
	<head/>
	<body>
		<a name="a"/>
		<p>This link goes <a href="vb">downward.</a></p>
		<br/>
		<p>Reduce the size of the window to verify the link really works.</p>
		<br/>
		<a name="b"/>
		<p>This link goes <a href="^a">upward.</a>
		</p>
	</body>
</html>

Целевой документ выглядит так же, за исключением элементов, приведенных в листинге 4.

Листинг 4. Целевой документ (в samples/linkUpDown.html)
   … <a href="#b">v downwards.</a> …
   … <a href="#a">^ upwards.</a> …

Директивы

В исходном документе можно расставить директивы, указывающие таблице стилей, что делать. Они принадлежат другому пространству имен (префикс a: в примере) и не копируются в целевой документ.

В листинге 5 тег директивы a:ref, размещаемой в любом месте исходного документа, создает сноску.

Листинг 5. Таблица стилей (в samples/footnote.xsl)
<s:stylesheet
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:a="http://sourceforge.net/projects/arbalo/"
	xmlns:h="http://www.w3.org/1999/xhtml"
	xmlns:s="http://www.w3.org/1999/XSL/Transform"
	version="1.0"
>
	<s:import href="common.xsl"/>
	<s:template match="h:body">
		<s:copy>
			<s:apply-templates select="@*|node()"/
			<!-- поместить сноску в конце,
			если отсутствует директива a:references -->
			<s:if test="not(descendant::a:references)">
				<s:call-template name="references"/>
			</s:if>
		</s:copy>
	</s:template>
	
	<s:template match="a:ref">
		<s:variable
			name="number"
			select="count(preceding::a:ref) + 1"/>
		<a name="ref-{$number}"></a>
		<a class="footnote" href="#reference-{$number}">
			<s:value-of select="concat('v ',$number)"/>
		</a>
	</s:template>
	<!-- если директива a:reference отсутствует,
	предположим, что она находится в конце тела -->
	<s:template match="a:references" name="references">
		<hr/>
		<s:for-each select="//a:ref">
			<s:variable name="number" select="count(preceding::a:ref) + 1"/>
			<p>
				<a name="reference-{$number}"></a>
				<a class="footnote" href="#ref-{$number}">
					<s:value-of select="concat(' ^',$number)"/>
				</a>
				<s:apply-templates/>
			</p>
		</s:for-each>
	</s:template>
</s:stylesheet>

При помощи директивы a:references в исходном документе шаблон под названием references размещает сноску там, где шаблон совпадает с директивой. Если такая директива отсутствует, первый шаблон, совпадающий с body, размещает сноски в конце body путем вызова того же шаблона под именем references. В обоих случаях отображается содержимое сносок, генерируются и отмечаются стрелками вверх ссылки, направленные из сноски на содержимое.

Второй шаблон, совпадающий с a:ref, создает ссылку на сноску со стрелкой вниз. Сноска нумеруется. Ее содержимое здесь игнорируется.

Атрибут class="footnote" разрешается после XSLT-преобразования CSS-таблицей стилей, ссылка на которую находится в XSLT-таблице стилей common.xsl.

Исходный документ в листинге 6 использует директиву a:ref для создания сносок.

Листинг 6. Исходный документ (в samples/footnote.xml)
<?xml-stylesheet href="footnote.xsl" type="text/xsl"?>
<html
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:a="http://sourceforge.net/projects/arbalo/"
>
	<head/>
	<body>
		<p>
			This example looks a little scientific
			<a:ref>
				From Latin
				<em>scientia</em>
			</a:ref>
			and academic
			<a:ref>From Greek akademia</a:ref>.
		</p>
		<p>
			Do you know why?
			<a:ref>
				It uses
				<em>footnotes</em>.
			</a:ref>
		</p>
		<p>Reduce size of window to verify links are generated.</p>
		
	
	</body>
</html>

Целевой документ содержит внизу список сносок, как в листинге 7.

Листинг 7. Целевой документ (в samples/footnote.html)
<html
	xmlns="http://www.w3.org/1999/xhtml"
   xmlns:h="http://www.w3.org/1999/xhtml"
   xmlns:a="http://sourceforge.net/projects/arbalo/">
   <head><link type="text/css" rel="stylesheet" href="common.css"/></head>
   <body>
      <p>This example looks a little scientific
         <a name="ref-1"/><a href="#reference-1" class="footnote">v 1</a>
         and academic.
         <a name="ref-2"/><a href="#reference-2" class="footnote">v 2lt;/a>
      </p>
      <p>Do you know why?
         <a name="ref-3"/><a href="#reference-3" class="footnote">v 3</a>
      </p>
      <p>Reduce size of window to verify links are generated.</p>
      br/><br/>
   <hr/>
   <p><a name="reference-1"/><a href="#ref-1" class="footnote"> ^1</a>
      From Latin
      <em>scientia</em>
   </p>
   <p><a name="reference-2"/>
      <a href="#ref-2" class="footnote"> ^2</a>From Greek akademia</p>
   <p><a name="reference-3"/><a href="#ref-3" class="footnote"> ^3</a>
      It uses
      <em>footnotes</em>.
   </p>
   </body>
</html>

Выход за пределы исходного документа

Существует возможность обращаться к частям других исходных документов. Директива a:include включает элемент, который может принадлежать другому исходному документу, и преобразует его (см. листинг 8).

Листинг 8. Таблица стилей (в samples/include.xsl)
<s:stylesheet
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:a="http://sourceforge.net/projects/arbalo/"
	xmlns:s="http://www.w3.org/1999/XSL/Transform"
	version="1.0"
>
	<s:import href="common.xsl"/>
	<s:template	match="a:include">
		<s:choose>
			<s:when test="0!=string-length(@src)">
				<s:apply-templates
					select="document(@src)//*[@id=current()/@refid]"/>
			</s:when>
			<s:when test="not(@src) and //a:default[1]/@src">
				<s:apply-templates
select="document(//a:default[1]/@src)//*[@id=current()/@refid]"/>
			</s:when>
			<s:when test="0=string-length(@src) or not(//a:default[1]/@src)">
				<s:apply-templates
					select="//*[@id=current()/@refid]"/>
			</s:when>
		</s:choose>
	</s:template>
</s:stylesheet>

Директива a:include в исходном документе ссылается на id исходного элемента. Документ, из которого берется элемент, указывается в атрибуте src. Если атрибут отсутствует, используется атрибут src директивы a:default. Если атрибута src нет вообще, используется тот же самый исходный документ. Таким образом, refid ссылается на id, чтобы устранить бесконечную рекурсию.

Импортируемый элемент может иметь сложный тип и преобразуется после включения (apply-templates). Примеры приведены в листингах 9, 10 и 11.

Листинг 9. Исходный документ (в samples/include.xml)
<?xml-stylesheet href="include.xsl" type="text/xsl"?>
<html
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:a="http://sourceforge.net/projects/arbalo/">
	<head>
		<a:default src="includedY.xml"/>
	</head>
	<body>
		<p>The following text is included:</p>
		<a:include refid="x" src="includedX.xml"/>
		<a:include refid="y1"/>
		<p id="i">double</p>
		<a:include refid="y2"/>
		<a:include refid="i" src="/>
	</body>
</html>
Листинг 10. Фрагмент исходного документа (в samples/includeY.xml)
	<h2 id="y2">I'm the <em>included</em> h2</h2>
	<h1 id="y1">I'm the <em>included</em> h1</h1>
Листинг 11. Целевой документ (в samples/include.html)
	<body>
		<p>The following text is included:</p>
		<p id="x">I'm the <em>included</em> paragraph.</p>
		<h1 id="y1">I'm the <em>included</em> h1</h1>
		<p id="i">double</p>
		<h2 id="y2">I'm the <em>included</em> h2</h2>
		<p id="i">double</p>
	</body>
</html>

Главный документ и навигация

Предположим, у нас есть презентация из нескольких страниц с главным документом, содержащим заголовки страниц и ссылки на них. Можно сгенерировать полную навигацию - с каждой страницы на любую другую, а также на предыдущую и последующую страницы. Подробный рассказ об этом выходит за рамки данной статьи, но в разделе Ресурсы приведены ссылки на HTML-презентации, использующие главный документ. Скомпилированная версия получается путем замены .xml на .html. Просмотрите в браузере довольно аккуратно выполненный исходный файл .xml. Вас удивит, насколько много кода в нем сгенерировано автоматически.


Интерпретация и компиляция

Интерпретация – это ситуация, когда страница является XML-файлом (расширение файла .xml, тип содержимого text/xml или application/xml), а XSLT-таблица стилей, на которую ссылается инструкция по обработке, выполняется в браузере.

Компиляция означает, что браузер видит HTML (расширение файла .html, тип содержимого text/html), который был преобразован из XML в вашей среде разработки или, непосредственно перед запросом страницы, на сервере. Хорошо известны XSLT-процессоры Xalan и Saxon.

Будущее за интерпретацией. Все современные браузеры поддерживают XSLT, и это дает некоторые преимущества:

  • При тестировании результаты видны немедленно. Просто нажмите кнопку F5 в каждом тестируемом браузере, чтобы отобразить изменения исходной страницы, CSS и XSLT.
  • Объем информации, передаваемой клиенту, уменьшается.
  • Клиент видит чистую и аккуратную Web-страницу, поскольку информация обогащения еще не была сгенерирована.

Но есть и недостатки:

  • Старые браузеры могут не поддерживать XSLT. Если страница публикуется в управляемой среде (интрасеть), это не является проблемой.
  • Некоторые современные браузеры запрещают ссылаться в XSLT-таблице стилей на другую таблицу стилей, расположенную в другом каталоге.
  • Сочетание XSLT с другими функциональными возможностями, такими как SVG или iframe, может вызвать проблемы в некоторых браузерах.
  • Поскольку большинство браузеров не поддерживает XSLT 2.0 и готовящуюся к выпуску версию 3.0, новые функциональные возможности использовать нельзя. Ни if () then ... else из XPath 2.0 , ни пользовательские XPath-функции.

И при компиляции, и при интерпретации другие преобразования (CSS, JavaScript) страницы выполняются после XSLT-преобразования.


Заключение

В данной статье рассматривалось использование XSLT-таблиц стилей для обогащения XHTML-документов. Примеры, приведенные в данной статье, можно использовать в качестве отправной точки при создании своих собственных XSLT-таблиц стилей.


Загрузка

ОписаниеИмяРазмер
Статья и примеры в XML. 1xsl-stylesheets.zip29 КБ

Заметка

  1. Загружаемый файл содержит:

    Пример презентации, использующей XSLT-таблицы стилей (на немецком языке, но ссылки на переводы на другие языки генерируются интегрированной средой XSLT): http://zocher-regel.gmxhome.de/ArbaloSchlacht/11Drusus.xml.

    Этот же файл, но скомпилированный в XHTML: http://zocher-regel.gmxhome.de/ArbaloSchlacht/11Drusus.html.

    Описание интегрированной среды XSLT, используемой для данной статьи: http://home.arcor.de/juergen.regel/Arbalo/index.xml.

    W3C XML Path Language (XPath): http://www.w3.org/TR/xpath/.

    W3C XSL Transformations (XSLT): http://www.w3.org/TR/xslt.


Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Web-архитектура
ArticleID=823513
ArticleTitle=Использование XSLT в качестве таблицы стилей для HTML
publish-date=06292012