. В терминах XSLT, этот элемент является литеральным элементом результата: он не принадлежит пространству имен XSLT и поэтому при обработке будет просто скопирован в результирующий документ. Содержимое этого элемента будет также обработано и включено в его сгенерированную копию.
Содержимым элемента
message
является элемент
xsl:value-of
, который, в отличие от
message
принадлежит XSLT. Элемент
xsl:value-of
вычисляет XPath-выражение, заданное в его атрибуте
select
, и возвращает результат этого вычисления. XPath-выражение,
"."
, указанное в
select
, возвращает
ту самую часть узла, которая обрабатывается в данный момент, иначе говоря — элемент
msg
.
Переводя на русский язык все вышеперечисленное, можно сказать, что приведенное преобразование содержит единственное правило: если в документе встретится элемент
msg
, создать в выходящем документе элемент
message
и включить в него содержимое элемента
msg
.
Синтаксис XSLT, являющийся чистым XML, может показаться для языка программирования не совсем обычным, однако, как показывает практика, вряд ли какой другой синтаксис был бы более удобным. В конце концов, XSLT — это, прежде всего преобразование XML-документов, и уж на чем, как не на XML описывать правила этого преобразования. Кроме того, XML- формат самого преобразования позволяет использовать для его представления те же модели данных, что и для преобразуемых документов.
Совсем иным является язык XPath, который представлен в нашем примере лаконичным выражением
"."
. XPath не придерживается XML-синтаксиса, напротив, он скорее похож на синтаксис путей в операционных системах — в главе 4 мы покажем, насколько верно это сравнение.
В приведенном преобразовании участвовала и третья синтаксическая конструкция, которая называется в XSLT паттерном (от англ. pattern — образец). Паттерн
msg
, заданный в атрибуте
match
элемента
xsl:template
указывает, какая именно часть XML-документа должна быть обработана этим правилом. Синтаксически паттерны являются XPath-выражениями (но не наоборот), однако смысл их различается. XPath-выражения вычисляются и возвращают результат, паттерны же просто устанавливают соответствие некоторому образцу. В нашем преобразовании паттерн
msg
указывает, что шаблон должен обрабатывать только элементы
msg
и никакие другие.
Каждое из шаблонных правил может вызывать другие шаблонные правила — в этом случае результат выполнения вызванных шаблонов включается в результат выполнения шаблона, который их вызывал. Для того чтобы продемонстрировать этот принцип мы немного перепишем шаблон
"Hello, world!"
с тем, чтобы он возвращал результат в виде HTML-документа.
Листинг 2.2. Преобразование "Hello, world!"' с результатом в HTML
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>Message</title>
</head>
<body>
<xsl:apply-templates select="msg"/>
</body>
</html>
</xsl:template>
<xsl:template match="msg">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
</xsl:stylesheet>
Результат применения этого преобразования к документу
<msg>Hello, world!</msg>
иллюстрирует листинг 2.3.
Листинг 2.3.
Результат выполнения преобразования
<html>
<head>
<title>Message</title>
</head>
<body>
<b>Hello, world!</b>
</body>
</html>
В это преобразование мы добавили еще одно шаблонное правило:
<xsl:template match="/">
<html>
<head>
<title>Message</title>
</head>
<body>
<xsl:apply-templates select="msg"/>
</body>
</html>
</xsl:template>
Это правило определяет обработку корневого узла — в атрибуте
match
указан паттерн
"/"
, что соответствует корню документа. Шаблон создает элементы
html
,
head
,
title
,
body
и в последний включает результат применения шаблонов к элементу
msg
. Сравнивая тело этого шаблона с результатом выполнения преобразования, можно заметить, что процессор скопировал все элементы, не принадлежащие XSLT, не изменяя их, а элемент
xsl:apply-templates
выполнил, применив шаблон к элементу
msg
и включив в
body
результат (он выделен в листинге полужирным шрифтом).
Продемонстрированная возможность вызова одних правил из других, а также наличие в XSLT таких управляющих конструкций, как
xsl:if
,
xsl:choose
и
xsl:for-each
позволяет простым набором правил реализовывать очень сложную логику преобразования. В XSLT применяется один из основных принципов эффективной разработки: для того чтобы решить задачу, нужно разбить ее на более мелкие части и решить каждую из них по отдельности. Проблемой в данном случае является преобразование, и вместо того, чтобы описывать его целиком, XSLT позволяет определить простые правила обработки каждой из частей, связав эти правила логикой взаимных вызовов и управляющих конструкций.
Отсутствие "побочных" эффектов
Одним из краеугольных принципов XSLT, с которым, увы, нелегко смириться разработчику, работавшему только с процедурными языками, — это отсутствие "побочных" эффектов. Под побочными эффектами в данном случае понимаются изменения в окружении преобразования, которые отражаются на дальнейшем его выполнении.
Концепция отсутствия побочных эффектов берет начало в функциональном программировании, а оно, в свою очередь, в "чистых" математических функциях, не изменяющих своего окружения в процессе вычисления. Например, функция
f(x, у) > вернуть x + у;
будет чистой функцией. Сколько бы раз мы ее не вызывали, ее результат все равно будет равен сумме аргументов. Кроме того, результат вычисления f(f(x1, y1), f(x2, y2)) будет равен x1 + y1 + x2 + y2, в каком бы порядке мы не вычисляли эти функции: