Генеральный спонсор: Хостинг «Джино»

Система Orphus
Russian version
Добавить на Del.icio.us
English version
Добавить на Digg.com

 dkLab | Конструктор | Dklab_ShortXSLT: упрощенный синтаксис для XSLT с операторами вставки, if, else и т. д. 

Карта сайта :: Форум «Лаборатории» :: Проект «Денвер»
Проект «Orphus» :: Куроводство: наблы :: Конструктор


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. Это даже не утилита, а скорее стандарт, по которому могут быть написаны библиотеки.






Дмитрий Котеров, Лаборатория dk. ©1999-2014
GZip
Добавить на Del.icio.us   Добавить на Digg.com   Добавить на reddit.com