<xsclass="underline" template name="page">
<xsclass="underline" param name="foo"/>
<xsclass="underline" text>Text</xsclass="underline" text>
</xsclass="underline" template>
Переменные и параметры
Было бы слишком просто и слишком бесполезно лишь констатировать, что переменные и параметры в XSLT похожи между собой и сильно отличаются от переменных в других языках программирования. Мы попытаемся разобраться в этом вопросе несколько глубже — чем именно и ради чего конкретно переменные в XSLT обладают такими свойствами.
В классической книге Монти Бен-Ари "Языки программирования" [Бен-Ари 2000] приводится следующее определение переменной:
Переменная — это имя, присвоенное ячейке памяти или ячейкам, которые могут содержать представление конкретного типа (данных).
Затем следует комментарий:
Значение может изменяться во время выполнения программы.
Если немного сменить уровень абстракции, первая часть этого определения верна и по отношению к параметрам, и переменным XSLT (далее мы будем говорить просто "переменные", поскольку различия между ними на данный момент несущественны). Конечно, где-то там внутри реализации конкретного XSLT-процессора есть память, поделенная на ячейки, в которой процессор хранит информацию. Такие детали нас, естественно, не интересуют, ибо мы больше рассуждаем о логических, чем о физических моделях. В логической же модели переменная представляется как объект определенного типа, с которым связано имя, — по этому имени мы можем обращаться к объекту, использовать его значение и так далее. Иными словами, в XSLT под переменной понимается не более чем ассоциация между значением и именем, и если мы вдруг скажем, что переменная x имеет значение 5, это будет означать, что имя "x" связано объектом численного типа, значение которого равно 5. Заметим небольшую разницу с определением Бен-Ари: мы не говорим о том, что число 5 лежит в какой-то ячейке памяти (хотя, несомненно, оно так и есть) и что этой ячейке присвоено имя "x" — мы говорим об ассоциации между объектом и именем и только.
Теперь, когда более или менее ясно, что же мы имеем в виду под переменными, на новой строчке полужирным шрифтом напишем следующее:
Разработчикам, которые использовали в своей практике только процедурные языки и не имеют опыта функционального или логического программирования будет очень нелегко смириться с такой ситуацией. То, что переменные не могут быть изменены дискредитирует само название — переменные, ибо они уже более похожи на константы.
Практически во всех процедурных языках оператор присваивания вида
переменная = выражение
с незначительными вариациями работает приблизительно следующим образом:
□ сначала вычисляется присваиваемое выражение;
□ затем вычисляется адрес переменной;
□ затем значение, полученное на первом шаге, копируется в ячейки памяти, начиная с адреса, полученного на втором шаге присваивания.
В XSLT нет оператора присваивания. Переменным и параметрам никогда не присваиваются значения в приведенном выше смысле, объявление переменной или параметра лишь связывает указанное имя со значением некоторого выражения. Иными словами, объявление переменной есть создание ассоциации между объектом и именем.
В конце этой главы мы вернемся к неизменяемым переменным и попытаемся объяснить, почему их нельзя изменить — но прежде мы должны научиться их использовать.
Элемент xsclass="underline" variable
Синтаксис этого элемента в XSLT определен так:
<xsclass="underline" variable
name="имя"
select="выражение">
<!-- Содержимое: шаблон -->
</xsclass="underline" variable>
Для объявления переменных в XSLT служит элемент xsclass="underline" variable, который может как присутствовать в теле шаблона, так и быть элементом верхнего уровня. Элемент xsclass="underline" variable связывает имя, указанное в обязательном атрибуте name, со значением выражения, указанного в атрибуте select или с деревом, которое является результатом выполнения шаблона, содержащегося в этом элементе. В том случае, если объявление переменной было произведено элементом верхнего уровня, переменная называется глобальной переменной. Переменные, определенные элементами xsclass="underline" variable в шаблонах (то есть не на верхнем уровне) называются локальными переменными.
Таким образом, объявление переменной в XSLT происходит всего в два шага:
□ сначала вычисляется значение присваиваемого выражения;
□ затем полученное значение связывается с указанным именем.
Значение присваиваемого выражения вычисляется в зависимости от того, как был определен элемент xsclass="underline" variable:
□ если в элементе xsclass="underline" variable определен атрибут select, то значением присваиваемого выражения будет результат вычисления выражения, указанного в этом атрибуте;
□ если атрибут select не определен, но сам элемент xsclass="underline" variable имеет дочерние узлы (иными словами, содержит шаблон), значением определяемой переменной будет результирующий фрагмент дерева, полученный в результате выполнения содержимого xsclass="underline" variable;
□ если атрибут select не определен и при этом сам элемент xsclass="underline" variable пуст, значением параметра по умолчанию будет пустая строка.
Использовать значения, присвоенные переменным при инициализации, можно, указывая впереди имени переменной символ "$", например для переменной x — $x. В XPath-выражениях синтаксис обращения к переменным соответствует продукции VariableReference.
Имя переменной соответствует синтаксическому правилу QName, иными словами, оно может иметь вид имя или префикс:имя. Как правило, имена переменным даются без префиксов, однако в том случае, если префикс все же указан, переменная ассоциирует с некоторым объектом не простое, а расширенное имя. Соответственно, обращение к объекту должно будет производиться также посредством расширенного имени.
Область видимости переменных
Каждая из переменных имеет собственную область видимости (англ. scope) — область, в которой может быть использовано ее значение. Область видимости определяется следующим образом.
□ Областью видимости глобальной переменной является все преобразование, то есть значение переменной, объявленной элементом верхнего уровня, может быть использовано в преобразовании где угодно. К такой переменной можно обращаться даже до ее объявления, единственным ограничением является то, что переменная не должна определяться через собственное значение — явно или неявно.
□ Локальную переменную можно использовать только после ее объявления и только в том же родительском элементе, которому принадлежит объявляющий элемент xsclass="underline" variable. В терминах XPath область видимости локальной переменной будет определяться выражением
following-sibling:node()/descendant-or-self:node().
Для того чтобы до конца прояснить ситуацию, приведем несколько примеров.
Предположим, что мы определяем переменную с именем ID и значением 4 следующим образом: