Книга: Технология XSLT
Область видимости переменных
Разделы на этой странице:
Область видимости переменных
Каждая из переменных имеет собственную область видимости (англ. scope) — область, в которой может быть использовано ее значение. Область видимости определяется следующим образом.
? Областью видимости глобальной переменной является все преобразование, то есть значение переменной, объявленной элементом верхнего уровня, может быть использовано в преобразовании где угодно. К такой переменной можно обращаться даже до ее объявления, единственным ограничением является то, что переменная не должна определяться через собственное значение — явно или неявно.
? Локальную переменную можно использовать только после ее объявления и только в том же родительском элементе, которому принадлежит объявляющий элемент xsl:variable
. В терминах XPath область видимости локальной переменной будет определяться выражением
following-sibling:node()/descendant-or-self:node()
.
Для того чтобы до конца прояснить ситуацию, приведем несколько примеров.
Предположим, что мы определяем переменную с именем ID
и значением 4
следующим образом:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
<xsl:variable name="ID" select="4"/>
...
</xsl:stylesheet>
Несложно видеть, что здесь мы определили глобальную переменную, а значит, ее значение можно использовать в преобразовании в любом месте. Например, мы можем определить через нее другие глобальные переменные, либо использовать в шаблоне:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
<xsl:variable name="leaf" select="//item[@id=$ID]"/>
<xsl:variable name="ID" select="4"/>
<xsl:variable name="path" select="$leaf/ancestor-or-self::item"/>
...
</xsl:stylesheet>
Причем, как уже было сказано, глобальная переменная может быть использована и до объявления: в нашем случае переменная leaf
определяется через переменную ID
, a path
— через leaf
. Конечно же, не следует забывать и то правило, что переменные не могут объявляться посредством самих себя, явно или неявно. Очевидно, что объявление:
<xsl:variable name="ID" select="$ID - 1"/>
было бы некорректным ввиду явного использования переменной при собственном определении. Точно так же были бы некорректны определения:
<xsl:variable name="ID" select="$id — 1/>
<xsl:variable name="id" select="$ID + 1"/>
поскольку переменная ID
определяется через переменную id
, которая определяется через переменную ID
и так до бесконечности.
Дела с локальными переменными обстоят чуть-чуть сложнее. Для того чтобы объяснить, что же такое область видимости, обратимся к следующему преобразованию.
Листинг 5.22. Преобразование, использующее переменные i, j, k и gt
<xsl:stylesheet
version="1.0"
xmlns:xsl="... ">
<xsl:template match="/">
<xsl:variable
name="i"
select="2"/>
<xsl:variable
name="j"
select="$i - 1"/>
<xsl:if test="$i > $j">
<xsl:variable name="k">
<xsl:value-of select="$i"/>
<xsl:value-of select="$gt"/>
<xsl:value-of select="$j"/>
</xsl:variable>
<result>
<xsl:copy-of select="$k"/>
</result>
</xsl:if>
</xsl:template>
<xsl:variable name="gt">
is greater than
</xsl:variable>
</xsl:stylesheet>
В этом преобразовании определены три локальные переменные — i
, j
и k
и одна глобальная переменная — gt
. На следующих четырех листингах мы выделим серой заливкой область видимости переменной (то есть область, где ее можно использовать), а само определение переменной отметим полужирным шрифтом.
Листинг 5.23. Области видимости переменных i, j, k и gt
Область видимости переменной i
Область видимости переменной j
<xsl:stylesheet <xsl:stylesheet
version="1.0" xmlns:xsl="... "> version="1.0" xmlns:xsl="... ">
<xsl:template match="/"> <xsl:template match="/">
<xsl:variable name="i" <xsl:variable name="i"
select="2"/> select="2"/>
<xsl:variable name="j" <xsl:variable name="j"
select="$i - 1"/> select="$i - 1"/>
<xsl:if test="$i > $j"> <xsl:if test="$i > $j">
<xsl:variable name="k"> <xsl:variable name="k">
<xsl:value-of select="$i"/> <xsl:value-of select="$i"/>
<xsl:value-of select="$gt"/> <xsl:value-of select="$gt"/>
<xsl:value-of select="$j"/> <xsl:value-of select="$j"/>
</xsl:variable> </xsl:variable>
<result> <result>
<xsl:copy-of select="$k"/> <xsl:copy-of select="$k"/>
</result> </result>
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
<xsl:variable name="gt"> <xsl:variable name="gt">
is greater than is greater than
</xsl:variable> </xsl:variable>
</xsl:stylesheet> </xsl:stylesheet>
Область видимости переменной k
Область видимости переменной gt
<xsl:stylesheet <xsl:stylesheet
version="1.0" xmlns:xsl="... "> version="1.0" xmlns:xsl="... ">
<xsl:template match="/"> <xsl:template match="/">
<xsl:variable name="i" <xsl:variable name="i"
select="2"/> select="2"/>
<xsl:variable name="j" <xsl:variable name="j"
select="$i - 1"/> select="$i - 1"/>
<xsl:if test="$i > $j"> <xsl:if test="$i > $j">
<xsl:variable name="k"> <xsl:variable name="k">
<xsl:value-of select="$i"/> <xsl:value-of select="$i"/>
<xsl:value-of select="$gt"/> <xsl:value-of select="$gt"/>
<xsl:value-of select="$j"/> <xsl:value-of select="$j"/>
</xsl:variable> </xsl:variable>
<result> <result>
<xsl:copy-of select="$k"/> <xsl:copy-of select="$k"/>
</result> </result>
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
<xsl:variable name="gt"> <xsl:variable name="gt">
is greater than is greater than
</xsl:variable> </xsl:variable>
</xsl:stylesheet> </xsl:stylesheet>
В XSLT действует то же правило, что и во многих других языках программирования: нельзя дважды определять переменную с один и тем же именем. Однако и тут есть свои особенности.
? Имена двух глобальных переменных могут совпадать в том и только том случае, когда они имеют разный порядок импорта. Например, если переменные с одинаковыми именами определены в разных преобразованиях, одно из них может быть импортировано. В этом случае переменная будет иметь значение, которое задано элементом xsl:variable
со старшим порядком импорта.
? Допускается совпадение имен локальной и глобальной переменных — в этом случае в области видимости локальной переменной будет использоваться локальное значение, в области видимости глобальной (но не локальной) — глобальное значение. Иными словами, локальные переменные "закрывают" значения глобальных.
? Две локальные переменные могут иметь совпадающие имена в том и только том случае, если их области видимости не пересекаются.
Первое правило мы уже упоминали, когда разбирали порядок импорта: тогда мы сказали, что переменные со старшим порядком импорта переопределяют переменные с младшим порядком импорта. Это довольно важное обстоятельство, поскольку оно добавляет некоторые интересные возможности, но при этом также может породить скрытые ошибки.
Пример
Предположим, что в следующем преобразовании в шаблоне с именем choice
мы генерируем два элемента input
.
Листинг 5.24. Преобразование en.xsl
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="submit" select="'Submit'"/>
<xsl:variable name="reset" select="'Reset'"/>
<xsl:template name="choice">
<input type="button" value="{$submit}"/>
<xsl:text>
</xsl: text>
<input type="reset" value="{$reset}"/>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="choice"/>
</xsl:template>
</xsl:stylesheet>
Результатом этого преобразования будет следующий фрагмент:
<input type="button" value="Submit"/>
<input type="reset" value="Reset"/>
Для того чтобы перевести надписи на этих кнопках на другой язык достаточно просто переопределить переменные. Например, результатом выполнения следующего шаблона.
Листинг 5.25. Преобразование de.xsl
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="en.xsl"/>
<xsl:variable name="submit" select="'Senden'"/>
<xsl:variable name="reset" select="'Loeschen'"/>
</xsl:stylesheet>
будет тот же фрагмент, но уже на немецком языке:
<input type="button" value="Senden"/>
<input type="reset" value="Loeschen"/>
С другой стороны, переопределение переменных может быть и опасным: в случае, если отдельные модули разрабатывались независимо, совпадение имен глобальных переменных может привести к ошибкам. Для того чтобы такое было в принципе исключено, имя переменной следует объявлять в определенном пространстве имен, например:
<xsl:variable name="app:href" select="..."/>
<xsl:variable name="db:href" select="..."/>
В том случае, если префиксы app
и db
(которые, конечно же, должны быть объявлены) будут указывать на разные пространства имен, никакого конфликта между этими двумя переменными не будет.
Возвращаясь к теме совпадений имен переменных, продемонстрируем "скрытие" локальной переменной значения глобальной:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="i" select="1"/>
<xsl:template match="/">
<xsl:text>i equals </xsl:text>
<xsl:value-of select="$i"/>
<xsl:text>
</xsl:text>
<xsl:variable name="i" select="$i + 1"/>
<xsl:text>i equals </xsl:text>
<xsl:value-of select="$i"/>
</xsl:template>
</xsl:stylesheet>
Результатом выполнения этого шаблона будет:
i equals 1
i equals 2
Как можно видеть, объявление локальной переменной i
"скрыло" значение глобальной переменной i
. Более того, это преобразование любопытно еще и тем, что локальная переменная объявляется через глобальную — такое тоже допускается.
Рассмотрим теперь случай двух локальных переменных. Попробуем объявить две локальные переменные — одну за другой в следующем шаблоне:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="i" select="1"/>
<xsl:text>i equals </xsl:text>
<xsl:value-of select="$i"/>
<xsl:text>
</xsl:text>
<xsl:variable name="i" select="2"/>
<xsl:text>i equals </xsl:text>
<xsl:value-of select="$i"/>
</xsl:template>
</xsl:stylesheet>
В тексте этого шаблона мы выделили две области видимости двух переменных: серой заливкой — область видимости первой и полужирным шрифтом — область действия второй переменной. Вследствие того, что эти области пересекаются, шаблон будет некорректным — процессор выдаст сообщение об ошибке вида:
Failed to compile style sheet
At xsl:variable on line 9 of file stylesheet.xsl:
Variable is already declared in this template
Приведем теперь другое преобразование, в котором элементы xsl:variable
принадлежат двум братским элементам:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<p>
<xsl:variable name="i" select="1"/>
<xsl:text>i equals </xsl:text>
<xsl:value-of select="$i"/>
</p>
<p>
<xsl:variable name="i" select="2"/>
<xsl:text>i equals </xsl:text>
<xsl:value-of select="$i"/>
</p>
</xsl:template>
</xsl:stylesheet>
В этом случае никакого пересечения областей видимости нет, поэтому и ошибкой наличие в одном шаблоне двух локальных переменных с одинаковыми именами тоже не будет. Приведенное выше преобразование возвратит результат вида:
<p>
i equals 1
</p>
<p>
i equals 2
</p>
- 3.10.1. Область видимости функции и подъем
- Пример 19-1. Область видимости переменных
- Пример 22-8. Область видимости локальных переменных
- Вложенные области видимости
- 1.2. Область видимости переменной
- 2.4.2 Сцена (область видимости)
- Элемент : создание переменных
- Пример 19-2. Личные настройки пользователей
- Переменные
- Переменные и параметры