|
2009-02-28
Обсудить на форуме
Принять участие в разработке библиотеки/утилиты можно на GitHub.
Библиотека Dklab_ShortXSLT это система поддержки упрощенного
синтаксиса XSLT для встроенных в PHP классов XSLTProcessor и DOMDocument.
Фактически это компилятор с диалекта XSLT в стандартный XSLT, запускаемый "на лету"
и "прозрачно" для вызывающего кода (естественно, с кэшированием результата компиляции,
поэтому накладные расходы минимальны). Подключить Dklab_ShortXSLT к существующему
проекту на XSLT можно, написав несколько дополнительных строчек кода.
Dklab_ShortXSLT это совместимое расширение стандартного XSLT.
Поэтому везде, где вы используете XSLT, можно свободно подключить Dklab_ShortXSLT:
все имеющиеся шаблоны продолжат работать без изменений.
Синтаксис Dklab_ShortXSLT
Обычный синтаксис XSLT весьма громоздок, что оказывается неудобным при его
использовании в Web-программировании. Библиотека позволяет облегчить эту проблему.
Сравним стандартный XSLT с возможностями Dklab_ShortXSLT.
Фигурные скобки вне тэгов: {xpath}
Конструкцию "фигурные скобки" вида {выражение_xpath} в
Dklab_ShortXSLT можно использовать не только внутри атрибутов,
но и вне тэгов.
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
<xsl:template match="root">
<div title="{/some}">
{/some}
</div>
</xsl:template> |
<xsl:template match="root">
<div title="{/some}">
<xsl:value-of select="/some" />
</div>
</xsl:template> |
Или любое другое выражение XPath:
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
<xsl:template match="root">
<div>
{/some + /other}
</div>
</xsl:template> |
<xsl:template match="root">
<div>
<xsl:value-of select="/some + /other" />
</div>
</xsl:template> |
|
Естественно, замена не производится внутри XML-комментариев, а также тэгов <script> и <style>. Это касается и остальных конструкций Dklab_ShortXSLT.
|
Вставка значения языковой константы: {#const_name}
В многоязычных проектах, да и просто там, где тексты сайта выделены в отдельное
хранилище, удобно ссылаться на них через "языковые константы".
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
<xsl:template match="root">
{#hello}
</xsl:template> |
<xsl:template match="root">
<xsl:value-of select="php:function('getConst', 'hello')" />
</xsl:template> |
Языковые константы с параметрами: {#const_name(param)}
Иногда в текст константы нужно вставить некоторое значение. Например, если
языковая константа hello_name содержит "Привет, %s!", то вызов
getConst("hello_name", "Василий") сгенерирует строку "Привет, Василий!".
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
<xsl:template match="root">
{#hello_name(/name)}
</xsl:template> |
<xsl:template match="root">
<xsl:value-of select="php:function('getConst',
'hello', string(/name))" />
</xsl:template> |
Или даже так:
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
<xsl:template match="root">
{#name_is(/name, #years_old(/age))}
</xsl:template> |
<xsl:template match="root">
<xsl:value-of select="php:function('getConst',
'name_is', string(/name), php:function('getConst',
string(/age)))" />
</xsl:template> |
Условный оператор: {if} ... {elseif} ... {else} ... {/if}
В XSLT условный оператор одна из самых громоздких конструкций. Dklab_ShortXSLT позволяет
сократить его запись при использовании вне тэгов. (Внимание: внутри значений атрибутов этот
оператор не поддерживается.)
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
{if /some/node = 1}One{else}More{/if} |
<xsl:choose>
<xsl:when test="/some/node = 1">
One
</xsl:when>
<xsl:otherwise>
More.
</xsl:otherwise>
</xsl:choose> |
Цикл for-each: {for-each}
Хотя for-each и не является громоздким оператором, для полноты картины он также поддерживается.
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
{for-each /nodes/*}
Name: {./name}
{/for-each} |
<xsl:for-each select="/nodes/*">
Name: {./name}
</xsl:for-each> |
Вызов именованного шаблона: {call-template}
Блоки некоторого HTML-макета иногда удобно оформиить в виде именованных
XSLT-шаблонов. Шаблоны затем вызываются через xsl:call-template там,
где нужно вставить соответствующий блок.
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
{call-template draw-user name="./user/name" mode="'full'"} |
<xsl:call-template name="draw-user">
<xsl:with-param name="name" select="./user/name" />
<xsl:with-param name="mode">full</xsl:with-param>
</xsl:call-template> |
Автоматическая генерация exclude-result-prefixes
Обычно элемент <xsl:stylesheet> содержит определение нескольких пространств имен, которые, если
ничего не предпринять, попадают в результирующий HTML-документ, засоряя его. С этим можно бороться,
перечисляя префиксы пространств имен в атрибуте exclude-result-prefixes элемента <xsl:stylesheet>.
Однако очень легко пропустить какой-то из префиксов и не заметить этого. Dklab_ShortXSLT добавит
атрибут exclude-result-prefixes в <xsl:stylesheet> за вас.
| Конструкция Dklab_ShortXSLT |
Аналогичный стандартный XSLT |
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="http://php.net/xsl"
xmlns:func="http://exslt.org/functions"
/> |
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="http://php.net/xsl"
xmlns:func="http://exslt.org/functions"
exclude-result-prefixes="php func"
/> |
Остальные инструкции из стандартного XSLT
Библиотека Dklab_ShortXSLT лишь расширяет набор инструкций XSLT. При этом все стандартные
конструкции XSLT остаются доступными. Например, вы можете использовать
<xsl:value-of select="node" disable-output-escaping="yes" /> для вставки "сырого" HTML
в результирующий документ (конструкция {node} всегда вставляет "заквоченные" данные).
Подключение библиотеки
Для работы требуется создать объект Dklab_ShortXSLT, а затем передать его в
Dklab_DOMDocument, загружающий XSLT-шаблон в программу:
|
Листинг 1: Подключение Dklab_ShortXSLT
|
// Создаем препроцессор ShortXSLT с поддержкой языковых констант и exclude-result-prefixes.
$preproc = new Dklab_ShortXSLT("Dictionary::get", true);
// Создаем XSLT-документ и привязываем к нему препроцессор.
$xslDoc = new Dklab_DOMDocument();
$xslDoc->addPreprocessor(array($preproc, "process"));
// Устанавливаем директорию для кэширования.
$xslDoc->setCacheDir('/tmp/Dklab_ShortXSLT');
// Загружаем XSLT-шаблон.
$xslDoc->load('page.xsl');
// Передаем его XSLT-процессору.
$xsl = new XSLTProcessor();
$xsl->registerPHPFunctions();
$xsl->importStyleSheet($xslDoc);
// ...
// Далее используем $xsl для генерации HTML-страниц обычным способом. |
Пример использования библиотеки
Под конец рассмотрим пример работы с библиотекой (посмотреть результаты его работы).
|
Листинг 3: PHP-обработчик: page.php
|
<?php
require_once dirname(__FILE__) . '/../../lib/config.php';
require_once dirname(__FILE__) . '/../../Dklab_DOMDocument/lib/config.php';
require_once "Dklab/DOMDocument.php";
require_once "Dklab/ShortXSLT.php";
// Create ShortXSLT preprocessor with constant and
// exclude-result-prefixes support.
$preproc = new Dklab_ShortXSLT("Dictionary::get", true);
// Load XSLT template and assign the preprocessor.
$xslDoc = new Dklab_DOMDocument();
$xslDoc->addPreprocessor(array($preproc, "process"));
// Set cache directory. ATTENTION! It is not safe to set this
// directory in /tmp on shared (non-dedicated) hosting, because
// all web-server users may see and modify it. Use your own,
// secure path instead of /tmp.
$xslDoc->setCacheDir('/tmp/Dklab_ShortXSLT');
$xslDoc->load('page.xsl');
// Initialize the XSLT processor and assign the template.
$xsl = new XSLTProcessor();
$xsl->setParameter("", "debug", intval(@$_GET['debug']));
$xsl->registerPHPFunctions();
$xsl->importStyleSheet($xslDoc);
// Run the transformation.
$doc = new DOMDocument();
$doc->loadXML('<root><name>Vasily Pupkin</name></root>');
echo $xsl->transformToXML($doc);
/**
* Dictionary: implement site localization logic.
* Holds keys and corresponding text messages for substitutions.
*/
class Dictionary
{
/**
* A dictionary is commonly load from outside. But we place
* it here for demo purposes only.
*/
private static $_dictionary = array(
'MENU' => "Menu",
'MAIN' => "Main page",
'PAGE' => "Test page",
'HELLO' => "Good morning, %s!",
'SITE_NAME' => "Test site",
);
/**
* This function is an XSLT constant request callback.
* Each time ShortXSLT sees "#xxx" reference in the template,
* it replaces this reference to call to the preprocessor.
* It works even within templates included via xsl:include
* and xsl:import.
*/
static function get()
{
$args = func_get_args();
$key = array_shift($args);
if (!@$_GET['debug']) {
$value = isset(self::$_dictionary[$key])?
self::$_dictionary[$key] : "#{$key}#";
if ($args) {
$value = vsprintf($value, $args);
}
} else {
$value = "[ORIG:$key]";
}
return $value;
}
}
echo "<br><br><hr>";
show_source(__FILE__); |
|
Листинг 4: Главный шаблон страницы: page.xsl
|
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:import href="1_layout.xsl" />
<xsl:template name="body">
{#HELLO(/root/name)}
<h2>
{if $debug != 0}
<a href="page.php">Replace keys by TEXTS</a>
{else}
<a href="page.php?debug=1">Debug mode: show KEYS</a>
{/if}
</h2>
</xsl:template>
</xsl:stylesheet> |
|
Листинг 5: Включаемый шаблон макета: 1_layout.xsl
|
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="/">
<html>
<head><title>{#SITE_NAME}</title></head>
<body>
<div style="padding:6px; border: 2px solid black">
{#MENU}:
{for-each document('1_menu.xml')/menu/item}
<a href="{@url}">{.}</a>
<xsl:text> </xsl:text>
{/for-each}
</div>
<br/>
<xsl:call-template name="body" />
</body>
</html>
</xsl:template>
</xsl:stylesheet> |
Резюме
XSLT стандартный и идеологичный язык, который часто используют для создания HTML-шаблонов.
Однако в реальной практике все сталкиваются с одной и той же проблемой: громоздкостью языка.
Библиотеки Dklab_ShortXSLT и Dklab_DOMDocument позволяют несколько улучшить ситуацию
в этой области, заменяя наиболее часто используемые инструкции на их компактные эквиваленты.
Конечно, Dklab_ShortXSLT это лишь один из возможных сокращенных диалектов XSLT.
Вы можете придумать и реализовать свой собственный, более удобный (см. документацию Dklab_DOMDocument).
См. также другие продукты и стандарты, посвященные сокращению синтаксиса XSLT (к сожалению,
среди них нет ни одного решения для PHP):
- libSLAX: библиотека поддержки Си-подобного
синтаксиса создания XSLT-шаблонов. Разработчики пошли до конца: даже HTML-тэги нужно вставлять
в Си-подобном виде. На текущий момент (февраль 2009 г.) она еще весьма "сырая".
Отсутствует поддержка для PHP.
- ShoXS: A Shorter XSL-T Syntax. Это даже не утилита,
а скорее стандарт, по которому могут быть написаны библиотеки.
|
|
Пользуетесь? Нравится?.. Пожертвуйте!
Пожертвование пойдет в качестве "спасибо" прямиком
на поддержание мотивации автора. А то он даже не знает, какое
количество людей пользуется той или иной библиотекой
или утилитой...
|