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