Skip to content
Sergei Nikitin edited this page Nov 14, 2011 · 14 revisions

Основной синтаксис

Простой вариант

В самом простом случае весь stylesheet представляет собой один кусок html'я:

<h1>Hello, World</h1>

Но нужно учитывать пару моментов. Во-первых, текстовые строки могут быть только внутри тегов. Во-вторых, фигурные скобки внутри атрибутов нужно удваивать. Например, так неправильно:

<h1>
    Hello, World
    <div onclick="return { foo: 42 }"></div>
</h1>

А так правильно:

<h1>
    "Hello, World"
    <div onclick="return {{ foo: 42 }}"></div>
</h1>

Непростой вариант

Простой вариант

<h1>Hello, World</h1>

на самом деле является сокращением для

match / {
    <h1>Hello, World</h1>
}

Т.е. весь stylesheet в этом случае представляет собой один шаблон, матчащийся на /.

Комментарии

Бывают блочные:

/* Block comments. */

/*
    Block
    comments.
*/

И строчные:

// Line comments.

$a = 42 // Line comments.

При этом важно помнить:

  • Блочные комментарии могут быть только там, где могут быть необязательные пробелы.

  • Строчные комментарии могут быть только там, где может быть перевод строки.

Блоки, выражения, определения

block — это несколько выражений и определений, ограниченных фигурными (тело шаблона, функции, а также операторов if и for) или круглыми скобками.

Кроме того, весь stylesheet целиком является блоком.

Внутри блоков могут быть:

  • определения шаблонов, функций и переменных;

  • xml-фрагменты и xml-атрибуты;

  • операторы if, for и apply (блочные выражения);

  • скалярные выражения (инлайновые выражения).

Каждый блок определяет область видимости переменных и функция, в нем определенных.

$a = 42
(
    $a = 73 // внутри этого блока переменная $a переопределена.
    $b = "Hello"
)
// переменная $b здесь уже не определена.

"Однострочный" синтаксис

Есть четкое правило: одна строка — одно выражение/оператор/конструкция/...

При этом внутри выражения может встретиться block, завернутый в фигурные или круглые скобки, в котором может быть несколько выражений, разделенных переводом строки. Но если не учитывать содержимое этих блоков, все остальное будет на одной строке:

match / { ... }

function foo() { ... }

if (42) { ... } else { ... }

for item { ... }

$a = ( ... )

Вот так неправильно:

match /
{
    ...
}

if (42)
    "Hello, World"

$a =
    (
        ...
    )

Перевод строки может быть только между выражениями.

Определения шаблонов, функций и переменных

Шаблоны

Аналог xsl:template. Принцип действия шаблонов такой же, как и в xslt.

Синтаксис:

match jpath body
match jpath : mode body

jpath — это несколько урезанный аналог xpath.

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

match page {
    <h1>
        apply . : title
    </h1>
}

match page : title "Hello, World"

Функции

Аналог именованных шаблонов в xslt:

// Функция без параметров.
function title() {
    <h1>
        title // Текущий контекст совпадает с контекстом вызова.
    </h1>
}

// Функция с параметрами.
function foo(a, b) {
    if ($a > $b) {
        <b>{ $a + $b }</b>
    } else {
        <i>{ $a - $b }</i>
    }
}

match / {
    title(page)
    foo(3, 4)
}

Переменные

Аналог xsl:variable.

$a = 42

$b = "Hello"

$c = (
    <h1>
        "Hello, { username }"
    </h1>
)

Важно Переменные, как и в xslt, неизменяемы.

XML-выражения

XML-фрагменты

Строка, начинающаяся с символа < (пробелы в начале не учитываются, конечно), представляет собой xml-фрагмент. При этом содержимое строки целиком не обязано быть well-formed. Но внутри любого блока сумарный xml должен быть well-formed. При это текстовые ноды допускаются только внутри well-formed фрагментов.

<h1>Hello, World</h1>

var xml = (
    <h1>
        "Hello, { $username }"
    </h1>
)

Вот тут все хорошо:

<b><i>Hello</i>
    ", World"
</b>

Текстовая нода Hello находится внутри well-formed фрагмента <i>...</i> (вся строка целиком не является well-formed).

А здесь ошибка:

<b><i>Hello     // Ошибка! "Висящая" текстовая нода.
, World</i></b> // Ошибка! Это вообще не xml-строка.

Внутри каждого блока вида { ... } или ( ... ) xml должен быть well-formed:

$xml = (
    <h1>
        "Hello"

    // Ошибка! Не well-formed xml внутри блока.
    // Здесь должен быть закрывающий тег </h1>.
)

match / {
    <h1>
        "Hello"

    // Ошибка!
}

if (42) <h1> // Ошибка! Выражение <h1> не well-formed.

XML-атрибуты

Аналог xsl:attribute.

Синтаксис:

@name = expr
@name += expr

Пример:

<div>
    @class = "b-folder"
</div>

Можно добавить что-нибудь к "дефолтному" значению атрибута:

<div class="b-folder">
    if (user) {
        @class += " b-folder-user"
    }
</div>

Тоже самое, но по-другому:

<div>
    @class = "b-folder"
    if (user) {
        @class += " b-folder-user"
    }
</div>

И еще по-другому:

<div>
    @class = (
        "b-folder"
        if (user) " b-folder-user"
    )
</div>

Интерполяция выражений

Внутри всех строковых литералов и текстовых нод фрагменты { ... } заменяются на значение выражения, находящегося внутри { ... }:

<h1>Hello, { $username }</h1>

"Hello, { $username }"

<h1 class="b-header-{ type }">

Чтобы вывести символы { и } их нужно удвоить:

<h1>Hello, {{ username }}</h1> // <h1>Hello, { username }</h1>

Блочные выражения

if

Аналог xsl:if.

Синтаксис:

if expr body
if expr body else body

expr должно быть инлайновым и [[types | иметь тип boolean]] (или же приводиться к boolean).

Пример:

if ($count > 0) {
    <div class="b-count">{ $count }</div>
}

if ($username) {
    "Hello, { $username }"
} else {
    "Hello"
}

if (42) "Hello"

for

Аналог xsl:for-each.

Синтаксис:

for expr body

expr должно быть инлайновым выражением и [[types | иметь тип nodeset]].

Например:

<ul>
    for items/item {
        <li>{ title }</li>
    }
</ul>

@class = (
    "b-item"
    for attr " b-item-{ . }"
)

apply

Аналог xsl:apply-templates.

Синтаксис:

apply expr
apply expr : mode

expr должно быть инлайновым выражением и [[types | иметь тип nodeset]].

Например:

apply items/item

apply /page/message/message[ new ] : message-title

apply $items/item

apply folders()/folder[1]

Аналога для <xsl:apply-templates/> без параметров нет. Как вариант просто:

apply *

Составное выражение

$html = (
    <h1>Hello, { username }</h1>
    <ul>
        @class = apply . : class
        apply items/item
    </ul>
)

Блочные выражения в качестве выражения

Например:

$items = for items/item {
    <li>{ title }</li>
}

$title = if (/page/title) {
    <h1>{ /page/title }</h1>
} // А если условие не выполняется, то значением $title будет пустая строка.

$result = apply page/folders : block

Скалярное выражение

Аналог xsl:value-of и xsl:text:

"Hello, { username }"

42

$a + $b

/page/title

"Hello, ", username // Список выражений (аналог concat в xslt)
Clone this wiki locally