-
Notifications
You must be signed in to change notification settings - Fork 28
syntax
В самом простом случае весь 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-фрагмент.
При этом содержимое строки целиком не обязано быть 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.
Аналог 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>
Аналог 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"
Аналог xsl:for-each
.
Синтаксис:
for expr body
expr
должно быть инлайновым выражением и [[types | иметь тип nodeset
]].
Например:
<ul>
for items/item {
<li>{ title }</li>
}
</ul>
@class = (
"b-item"
for attr " b-item-{ . }"
)
Аналог 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)