<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Toivonen`s Blog</title>
	<atom:link href="http://toivonen.ru/feed" rel="self" type="application/rss+xml" />
	<link>http://toivonen.ru</link>
	<description>Just another WordPress weblog</description>
	<pubDate>Fri, 20 Jan 2012 19:00:59 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Тестовые задания по JavaScript. Замыкания</title>
		<link>http://toivonen.ru/notes/problems/closure-tasks.html</link>
		<comments>http://toivonen.ru/notes/problems/closure-tasks.html#comments</comments>
		<pubDate>Fri, 20 Jan 2012 19:00:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Задачи]]></category>

		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=267</guid>
		<description><![CDATA[ Все публикуемые тестовые задания&#160;&#8212; эксперимент по подготовке одного человека  

Замыкание&#160;&#8212; когда функции представляют собой комбинацию кода и области видимости, в которой этот код исполняется.
Все JavaScript функции являются замыканиями. Основной фан при экспорте вложенной функции за пределы области видимости, в которой она была определена.

Теоретическую информацию можно прочесть в блоге Дмитрия Сошникова о замыканиях в [...]]]></description>
			<content:encoded><![CDATA[<p> Все публикуемые тестовые задания&nbsp;&mdash; эксперимент по подготовке одного человека <img src='http://toivonen.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<blockquote>
<p>Замыкание&nbsp;&mdash; когда функции представляют собой комбинацию кода и области видимости, в которой этот код исполняется.<br />
Все JavaScript функции являются замыканиями. Основной фан при экспорте вложенной функции за пределы области видимости, в которой она была определена.</p>
</blockquote>
<p>Теоретическую информацию можно прочесть в <a href="http://dmitrysoshnikov.com/ecmascript/ru-chapter-6-closures/#zamyikanie">блоге Дмитрия Сошникова о замыканиях в ECMA</a>.</p>
<p>Разбор задач, а также вторая порция по этой теме, будут опубликованы в понедельник.</p>
<ol>
<li>Что окажется в консоли?
<div class="codecolorer-container javascript " style="overflow:auto;white-space:nowrap;width:auto"><div class="javascript codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="kw2">var</span> i<span class="sy0">;</span><br />
<span class="kw1">for</span><span class="br0">&#40;</span>i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="nu0">10</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; setTimeout<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>console.<span class="me1">log</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="sy0">;</span><span class="br0">&#125;</span><span class="sy0">,</span> <span class="nu0">1000</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div></div>
</li>
<li>Каким будет результат?
<div class="codecolorer-container javascript " style="overflow:auto;white-space:nowrap;width:auto"><div class="javascript codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="kw2">var</span> x <span class="sy0">=</span> <span class="st0">&quot;глобальная&quot;</span><span class="sy0">;</span><br />
<span class="kw2">function</span> g_func<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">var</span> x <span class="sy0">=</span> <span class="st0">&quot;локальная&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">function</span> l_func<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw3">alert</span><span class="br0">&#40;</span>x<span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> l_func<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
func <span class="sy0">=</span> g_func<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
func<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></div>
Почему?</li>
<li>Какое значение будет у arr[2](), arr[arr.length]()?
<div class="codecolorer-container javascript " style="overflow:auto;white-space:nowrap;width:auto"><div class="javascript codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="kw2">function</span> create<span class="br0">&#40;</span>number<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">var</span> arr <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw2">var</span> i<span class="sy0">=</span><span class="nu0">1</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>number<span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arr<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw3">alert</span><span class="br0">&#40;</span>i<span class="sy0">*</span>i<span class="br0">&#41;</span> <span class="br0">&#125;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> arr<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<span class="kw2">var</span> arr <span class="sy0">=</span> create<span class="br0">&#40;</span><span class="nu0">100</span><span class="br0">&#41;</span><span class="sy0">;</span></div></div>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/notes/problems/closure-tasks.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>10 ошибок XSLT-программистов</title>
		<link>http://toivonen.ru/books-articles/xslt-articles/10-xslt-mistakes.html</link>
		<comments>http://toivonen.ru/books-articles/xslt-articles/10-xslt-mistakes.html#comments</comments>
		<pubDate>Thu, 12 Aug 2010 13:13:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Статьи об XSLT]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=237</guid>
		<description><![CDATA[ Перевод статьи &#171;The ten most common XSLT programming mistakes&#187;, ссылка на которую недавно опубликована в клубе XSLT на Я.ру.
Недавно я сказал в ответ пользователю, что он попадает в наиболее распространённые ловушки для программистов на XSLT. Вместо того, чтобы быть раздраженным, что я почти ожидал, он поблагодарил меня и спросил, не мог бы я рассказать [...]]]></description>
			<content:encoded><![CDATA[<p> Перевод <a href="http://saxonica.blogharbor.com/blog/_archives/2010/6/11/4550606.html">статьи &laquo;The ten most common XSLT programming mistakes&raquo;</a>, ссылка на которую недавно опубликована в <a href="http://clubs.ya.ru/xslt/">клубе XSLT на Я.ру</a>.</p>
<p>Недавно я сказал в ответ пользователю, что он попадает в наиболее распространённые ловушки для программистов на XSLT. Вместо того, чтобы быть раздраженным, что я почти ожидал, он поблагодарил меня и спросил, не мог бы я рассказать ему о двугих ловушках. Некоторые из нас помогают людям избежать этих ловушек в течение многих лет, но, несмотря на это, я не припомню, чтобы видел список таких ловушек. Так что я решил потратить полчаса, чтобы составить такой список.<br />
<span id="more-237"></span></p>
<ol>
<li>Обрабатывать элементы в дефолтном пространстве имён (namespace). Если исходный XML-документ содержит декларацию дефолтного пространства имён <em>xmlns="something"</em>, то каждый раз, когда вы ссылаетесь на имя элемента в XPath-выражении или значении атрибута match, вы должны ясно давать понять, что вы имеете в виду элементы из этого пространства имён. В XSLT 1.0 вы должны связать префикс с этим пространством имён (например <em>xmlns:p="something"</em> в элементе <em>xsl:stylesheet</em>) и затем везде использовать этот префикс, напимер, <em>match="p:chapter/p:section"</em>. В XSLT 2.0 есть альтернатива&nbsp;&mdash; задекларировать в элементе xslt:stylesheet <em>default-xpath-namespace="something"</em>.</li>
<li>Использование относительных путей. xsl:apply и xsl:for-each принимают текущий узел; в рамках &laquo;цикла&raquo; пути должны быть написаны относительно текущего узла. Например,
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;chapter&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;title&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span></div></div>
Распространённая ошибка&nbsp;&mdash; использование абсолютных путей внутри цикла (например <em>select="//title"</em>) или повторение имени контекстного узла в относительном пути (<em>select="chapter/title"</em>).</li>
<li>Переменные содержат значения, а не фрагменты синтаксических выражений. Некоторые люди думают, что ссылка на переменную $x подобна макросу, распространяющемуся и на синтаксис xPath-выражений путйм буквального замещения&nbsp;&mdash; как в языках типа shell. Это не так: вы можете использовать переменные только там, где вы можете использовать значение. Например, если $N содержит строку &#39;para&#39;, то выражение <em>chapter/$N</em> не означает того же, что и <em>chapter/para</em>. Вместо этого вам нужно <em>chapter/*[name()=$N]</em>. Если переменная содержит что-то более сложное, чем просто имя (например, запись xPath-пути), вам понадобится расширение, подобное saxon:evaluate(), чтобы вычислить это.</li>
<li>Шаблонные правила <em>xsl:apply-templates</em>&nbsp;&mdash; это не расширенные возможности языка для подвинутых пользователей. Это самые основные, фундаментальные конструкции в XSLT. Не откладывайте тот день, когда вы начнёте их использовать. Если вы не используете их, вы делаете свою жизнь излишне сложной.</li>
<li>XSLT принимает дерево на вход и отдаёт дерево на выходе. Непонимание этого является причиной многих разочарований, которые возникают у новичков в XSLT. XSLT не может обработать вещи, которые не представлены в дереве, предоставленном XML-парсером (области CDATA, ссылки на сущности (entity), XML-декларация), и не может сгенерировать эти вещи на выходе. Если вы думаете, что вам это необходимо, спросите &laquo;почему?&raquo;. Возможно что-то не так с вашими требованиями или замыслом.</li>
<li>Пространства имён (namespace)&nbsp;&mdash; это трудно. Нет лёгкого способа опровергнуть это. Возможно, это требует отдельной статьи. Разгадка в понимании модели пространств имён. Пространства имён проявляются в двух ипостасях:
<ol>
<li>Каждый элемент или атрибут имеет имя, состоящее из префикса, собственно имени и URI.</li>
<li>Элементы обладают узлами пространств имён, представляющими все префикс-uri соответствия в границах этого элемента.</li>
</ol>
Когда вы поймёте это, вы сможете понять особенности различных правил и их влияние на пространства имён в результирующем дереве. Чаще всего, всё, что вам нужно делать, это гарантировать, что создаваемые вами элементы находятся в верном пространстве имён, всё остальное произойдёт само собой.
</li>
<li>Не используйте <em>disable-output-escaping</em>. Некоторые люди используют эту магическую приправу, но не понимают, что она делает. Они надеются, что это может заставить код работать лучше. Этот атрибут только для профессионалов, и профессионалы используют это только как последнее средство спасения. В 95% случаях, если вы встретили в преобразовании <em>disable-output-escaping</em>, это говорит о том, что автор был новичком, не понимающим, что он делает.</li>
<li>Инструкция <em><xsl:copy-of></em> создаёт точную копию исходного дерева, пространств имён и всего остального. (Есть исключение&nbsp;&mdash; в XSLT 2.0 вы можете сказать <em>copy-namespaces="no"</em>). Если вы хотите скопировать дерево с изменениями, вы не можете использовать <em>xsl:copy-of</em>. Вместо этого используйте шаблон идентичного преобразования: шаблон, который использует создание поверхностной копии элемента и применяет <em>applies-templates</em> ко всем его потомкам, дополненный шаблонами, переопределяющими это поведение для отдельных элементов.</li>
<li>Не используйте
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;y&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span></div></div>
<p>Вместо этого используйте</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;x&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;y&quot;</span><span class="re2">/&gt;</span></span></div></div>
Последняя запись короче, более действенна при исполнении, и в любом случае она корректна.</li>
<li>Когда вам нужно найти информацию, используйте ключи. Также как и в случае с шаблонами, не откладывайте изучение использования ключей и не выбрасыйте их из головы как &laquo;продвинутую&raquo; возможность. Это важнейший инструмент разработки. Поиск информации без использования ключей сродни забиванию гвоздей отвёрткой.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/books-articles/xslt-articles/10-xslt-mistakes.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Bespin Embedded с белой темой</title>
		<link>http://toivonen.ru/notes/bespin-embedded-whitetheme.html</link>
		<comments>http://toivonen.ru/notes/bespin-embedded-whitetheme.html#comments</comments>
		<pubDate>Tue, 20 Jul 2010 18:51:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Заметки]]></category>

		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=240</guid>
		<description><![CDATA[ В процессе создания своей версии Bespin Embedded мне показалось, что в документации не достаточно хорошо освещены некоторые моменты. Поэтому далее последует небольшой мануал для тех, кто решит повторить мой путь.

Я использовала последнюю на данный момент версию 0.9a1, которая заявлена как &#171;альфа&#187;. Но это не имеет значения, потому что предыдущая версия тоже альфа. Но у [...]]]></description>
			<content:encoded><![CDATA[<p> В процессе создания своей версии Bespin Embedded мне показалось, что в документации не достаточно хорошо освещены некоторые моменты. Поэтому далее последует небольшой мануал для тех, кто решит повторить мой путь.<br />
<span id="more-240"></span></p>
<p>Я использовала последнюю на данный момент версию 0.9a1, которая заявлена как &laquo;альфа&raquo;. Но это не имеет значения, потому что предыдущая версия тоже альфа. Но у 0.9 нет опубликованных Embedded-архивов, так что собирать свой редактор придётся самостоятельно. Исходники можно <a href="http://ftp.mozilla.org/pub/mozilla.org/labs/bespin/Embedded/BespinEmbedded-0.9a1.tar.gz">скачать с их сайта</a>.</p>
<p>Для сборки необходимо создать .json-файл, например, mybespin.json. В этом файле декларируются необходимые настройки собираемого редактора.</p>
<div class="codecolorer-container javascript " style="overflow:auto;white-space:nowrap;width:auto"><div class="javascript codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;output_dir&quot;</span><span class="sy0">:</span> <span class="st0">&quot;tmp&quot;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;plugins&quot;</span><span class="sy0">:</span> <span class="br0">&#91;</span><span class="st0">&quot;embedded&quot;</span><span class="sy0">,</span> <span class="st0">&quot;whitetheme&quot;</span><span class="sy0">,</span> <span class="st0">&quot;syntax_manager&quot;</span><span class="sy0">,</span> <span class="st0">&quot;html&quot;</span><span class="sy0">,</span> <span class="st0">&quot;js_syntax&quot;</span><span class="sy0">,</span> <span class="st0">&quot;stylesheet&quot;</span><span class="br0">&#93;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;include_sample&quot;</span><span class="sy0">:</span> <span class="kw2">true</span><br />
<span class="br0">&#125;</span></div></div>
<p>Мой вариант позволяет иметь белую тему и подсветку html. Также обязательно необходимо указать плагины для подсветки js и css, т.к. этот код может входить в html.</p>
<p>Затем необходимо запустить следующую команду:</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">python dryice.py mybespin.json</div></div>
<p>В результате в папке tmp окажется собранный редактор. При его инициализации необходимость использования белой темы и подсветки указывается в настройках:</p>
<div class="codecolorer-container javascript " style="overflow:auto;white-space:nowrap;width:auto"><div class="javascript codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="br0">&#123;</span><br />
&nbsp; &nbsp; syntax<span class="sy0">:</span> <span class="st0">'html'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; settings<span class="sy0">:</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; tabstop<span class="sy0">:</span> <span class="nu0">4</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; theme<span class="sy0">:</span> <span class="st0">'white'</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div></div>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/notes/bespin-embedded-whitetheme.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>2.4 Структура преобразования</title>
		<link>http://toivonen.ru/books-articles/xslt-by-orelly/hello_world_example/introduction/stylesheet-structure.html</link>
		<comments>http://toivonen.ru/books-articles/xslt-by-orelly/hello_world_example/introduction/stylesheet-structure.html#comments</comments>
		<pubDate>Tue, 08 Jun 2010 14:46:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Первое преобразование, введение]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=226</guid>
		<description><![CDATA[ В заключительной частьи нашего представления XSLT мы посмотрим на содержание самих преобразований. Мы поясним всё в наших преобразованиях и обсудим другие подходы, которые мы могли бы применить.
2.4.1 Элемент &#60;xsl:stylesheet&#62;
Элемннт xsl:stylesheet&#160;&#8212; это обычно корневой элемент XSLT-преобразования.
&#60;xsl:stylesheet
 &#160; &#160;xmlns:xsl=&#34;http://www.w3.org/1999/XSL/Transform&#34;
 &#160; &#160;version=&#34;1.0&#34;&#62;

Прежде всего, элемент xsl:stylesheet определяет версию XSLT, которую мы будем использовать, в соответствии с определением пространства [...]]]></description>
			<content:encoded><![CDATA[<p> В заключительной частьи нашего представления XSLT мы посмотрим на содержание самих преобразований. Мы поясним всё в наших преобразованиях и обсудим другие подходы, которые мы могли бы применить.</p>
<h3>2.4.1 Элемент &lt;xsl:stylesheet&gt;</h3>
<p>Элемннт <em>xsl:stylesheet</em>&nbsp;&mdash; это обычно корневой элемент XSLT-преобразования.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:stylesheet</span></span><br />
<span class="sc3"> &nbsp; &nbsp;<span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp;<span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">&gt;</span></span></div></div>
<p><span id="more-226"></span><br />
Прежде всего, элемент <em>xsl:stylesheet</em> определяет версию XSLT, которую мы будем использовать, в соответствии с определением пространства имён <em>xsl</em>. Чтобы соответствовать спецификации XSLT, ваше преобразование всегда должно начинаться с этого элемента, определённого в точности так, как показано здесь. Некоторые процессоры, особенно Xalan, выдают предупреждающие сообщения, если ваш элемент <em>xsl:stylesheet</em> не содержит этих двух атрибутов с этими двумя значениями. Во всех примерах этой книги мы будем начинать преобразование с точно такого же элемента, определяя другие пространства имён в случае необходимости.</p>
<h3>2.4.2 Элемент &lt;xsl:output&gt;</h3>
<p>Далее мы определяем метод вывода. Спецификация XSLT задаёт три метода вывода: xml, html и text. Мы создаём HTML-документ, поэтому мы ходим использоваться метод вывода html. Вдобавок к этим трём методам XSLT-процессор может задавать свои собственные методы вывода, так что посмотрите документацию вашего XSLT-процессора на предмет каких-либо альтернатив.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:output</span> <span class="re0">method</span>=<span class="st0">&quot;html&quot;</span><span class="re2">/&gt;</span></span></div></div>
<p>С разными методами вывода используются разные атрибуты. Например, если мы используем метод xml, мы можем использовать <em>doctype-public</em> и <em>doctype-system</em>, чтобы определить его как публичный или локальный для использования в DTD (Document Type Declaration). Если вы используете методы xml или html, вы можете воспользоваться атрибутом indent, чтобы задать возможность ставить или нет дополнительные пробелы при выводе. Обсуждение элемента <em>xsl:output</em> в приложении A рассматривает все эти детали.</p>
<h3>2.4.3 Наш первый &lt;xsl:template&gt;</h3>
<p>Наш первый шаблон будет на <em>"/"</em>, это XPath выражение для корневого элемента документа.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">select</span>=<span class="st0">&quot;greeting&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<h3>2.4.4 &lt;xsl:template&gt; для &lt;greeting&gt;</h3>
<p>Второй &lt;xsl:template&gt;  элемент обрабатывает люой элемент &lt;greeting&gt; в нашем исходном XML-документе.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;greeting&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<h3>2.4.5 Встроенные правила шаблонов</h3>
<p>Хотя большинство преобразований, которые мы будем делать в этой книге, ясно определяют, как различные XML-элементы будут преобразованы, XSL задаёт несколько встроенных шаблонных правил, которые применяются при отсутствии каких-либо специальных правил. Эти правила имеют приоритет ниже, чем любые другие шаблоны, так что они всегда перезаписываются, когда вы задаёте свои собственные шаблоны. Встроенные шаблоны перечислены здесь.</p>
<h3>2.4.5.1 Встроенное правило для элементов и корневого узла</h3>
<p>Этот шаблон преобразует корневой элемент и любой из его потомков. Это преобразование гарантирует, что рекурсивное преобразование будет продолжено, даже если для данного элемента не определён никакой шаблон.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;*|/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Это означает, что если содержание документа выглядит так:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;x<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;y<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;z</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/y<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/z<span class="re2">&gt;</span></span></span></div></div>
<h3>2.4.5.2 Встроенные правила для mode</h3>
<p>Этот шаблон гарантирует, что элемент или корневой узел обрабатывается, невзирая на то, что любой mode может иметь влияние. (Смотрите пункт 4.3.2 в главе 4 для подробной информации об атрибуте mode).</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;*|/&quot;</span> <span class="re0">mode</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">mode</span>=<span class="st0">&quot;x&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<h3>2.4.5.3 Встроенный шаблон для текстовых узлов и атрибутов</h3>
<p>Этот шаблон копирует текст из всех текстовых узлов, а также атрибуты в результирующее дерево. Имейте в виду, что вы должны явно выбрать текстовые узлы и атрибуты, чтобы это правило было вызвано.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;text()|@*&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<h3>2.4.5.4 Встроенный шаблон для комментариев и управляющих инструкций</h3>
<p>Этот шаблон не делает ничего.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;comment()|processing-instruction()&quot;</span><span class="re2">/&gt;</span></span></div></div>
<h3>Встроенный шаблон для пространств имён (namespace)</h3>
<p>Этот шаблон не делает ничего.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;namespace()&quot;</span><span class="re2">/&gt;</span></span></div></div>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/books-articles/xslt-by-orelly/hello_world_example/introduction/stylesheet-structure.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Эффективное использование рекурсии в XSL</title>
		<link>http://toivonen.ru/books-articles/xslt-articles/recursion.html</link>
		<comments>http://toivonen.ru/books-articles/xslt-articles/recursion.html#comments</comments>
		<pubDate>Sat, 01 Aug 2009 14:32:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Статьи об XSLT]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=186</guid>
		<description><![CDATA[ Перевод статьи Use recursion effectively in XSL.
Введение в XSL-рекурсию и приёмы для оптимизации её использования.
Эффективное и рациональное использование XSL-преобразований требует понимания, как использовать XSL в качестве функционального языка, что означает понимание рекурсии. Эта статья знакомит с ключевыми идеями рекурсии и особенностей её использования в XSL. Также объяснены приёмы для оптимизации преобразования XML и избегания [...]]]></description>
			<content:encoded><![CDATA[<p> Перевод статьи <a href="http://www.ibm.com/developerworks/xml/library/x-xslrecur/">Use recursion effectively in XSL</a>.<br />
Введение в XSL-рекурсию и приёмы для оптимизации её использования.</p>
<p>Эффективное и рациональное использование XSL-преобразований требует понимания, как использовать XSL в качестве функционального языка, что означает понимание рекурсии. Эта статья знакомит с ключевыми идеями рекурсии и особенностей её использования в XSL. Также объяснены приёмы для оптимизации преобразования XML и избегания ошибок при использовании рекурсии. Каждая идея или метод сопровождаются примерами кода.<span id="more-186"></span></p>
<p>Сейчас в мире преобладают императивные языки программирования. Наиболее популярные языки&nbsp;&mdash; Java, C (и его различные виды), Visual Basic и другие&nbsp;&mdash; на высоком абстрактном уровне работают, в основном, одинаково: вы задаёте некоторые переменные, вызываете функции или операторы, которые меняют эти переменные, и возвращаете результат. Это сильное приближение к программированию, и это, конечно, не всё.</p>
<p>Языки программирования другой породы, пока менее привычной, по крайней мере также сильны как их процедурные &laquo;коллеги&raquo;. Эти языки названы <em>функциональными</em> или <em>декларативными</em> языками. Программы, написанные на этих языках, могут только однажды определить переменные, и никогда не могут поменять хранимое значение однажды определённой переменной. Язык программирования XSL и функциональный, и декларативный. Это означает, что разработчики, привыкшие писать на Java или C, и изучающие XSL часто чувствуют себя не в своей тарелке, применяя самые передовые особенности XSL.</p>
<p>Из-за роста важности как приложений, так и web-разработчиков и завязанности на XSL-технологию, эффективное использование XSL-преобразований не может быть проигнорировано. Так, наиболее важно научиться, как программировать в декларативной манере. Это подразумевает близкое знакомство с <strong>рекурсией</strong>, основанное на методах её эффективного использования и рационального решения текущих задач.</p>
<h2><strong>Введение в рекурсию на примере</strong></h2>
<p>Через использование рекурсивных функций декларативные языки способны предоставлять функциональность, подобную функциональности их императивных &laquo;коллег&raquo;. Это не значит, что императивные языки не могут использовать рекурсию. Большинство&nbsp;&mdash; могут. Разница в том, что декларативные языки используют рекурсию как основное средство деятельности, тогда как чаще всего это просто свойство в императивных языках. </p>
<p>Рассмотрим функцию, которая высчитывает факториал от некоторого положительного целого. Вкратце, факториал числа&nbsp;&mdash; это число, полученное путём умножения всех предшествующих ему чисел. Так, факториал от 4 (или 4!)&nbsp;&mdash; 1*2*3*4 = 24. Распечатка 1 показывает один из способов написать эту функцию на Java:</p>
<p><em>Распечатка 1. Решение задачи про факториал с использованием цикла на Java</em></p>
<div class="codecolorer-container java " style="overflow:auto;white-space:nowrap;width:auto"><div class="java codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="kw1">public</span> <span class="kw4">int</span> factorial<span class="br0">&#40;</span><span class="kw4">int</span> number<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>number <span class="sy0">&lt;=</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="kw1">return</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> result <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy0">=</span><span class="nu0">1</span><span class="sy0">;</span> i <span class="sy0">&lt;=</span> number<span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result <span class="sy0">*=</span> i<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> result<span class="sy0">;</span><br />
<span class="br0">&#125;</span></div></div>
<p>Пока это совершенно разумный код, он действительно пользуется тем фактом, что вы можете переопределить значения переменных в Java-программе. Без этой роскоши вы можете только решать задачу определением функций, как в Распечатке 2.</p>
<p><em>Распечатка 2. Решение задачи про факториал с использованием рекурсии на Java</em></p>
<div class="codecolorer-container java " style="overflow:auto;white-space:nowrap;width:auto"><div class="java codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="kw1">public</span> <span class="kw4">int</span> factorial<span class="br0">&#40;</span><span class="kw4">int</span> number<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>number <span class="sy0">&lt;=</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="kw1">return</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> number <span class="sy0">*</span> factorial<span class="br0">&#40;</span>number<span class="sy0">-</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div></div>
<p>Результаты вызова этих двух реализаций вычисления факториала одинаковы. Вызов функции <em>factorial()</em> в теле метода показывает, что вторая реализации использует рекурсию. Этот метод может быть визуально представлен как лестница. Программа многократно спускается вниз, вызывая саму себя, собирая статическую информацию для каждого вызова пока не упрется в условие выхода из рекурсии. Достигнув конца, она идёт обратно, возвращая различные состояния уже сделанных вызовов, объединяя информацию, собранную на пути вниз, для получения финального результата. Пример про факториал показан на рисунке.<br />
<img src="http://www.ibm.com/developerworks/xml/library/x-xslrecur/steps.gif" alt="Представление рекурсии в виде лестницы" /></p>
<p>В общем случае, рецепт создания рекурсивной функции включает в себя три ингредиента: условие выхода, код операции и рекурсивный вызов самого себя. В случае факториала, я вычисляю его для n путём вычисления факториала для n-1, n-2, n-3 и т.д. пока функция не достигнет условия выхода из серии&nbsp;&mdash; значения 1.</p>
<p>Так, если сейчас идея рекурсии ещё кажется немного смущающей, вы могли бы прервать чтение этой статьи и либо проследовать по некоторым ссылкам на эту тему в разделе <a href="http://www.ibm.com/developerworks/xml/library/x-xslrecur/#resources">Ресурсы</a>, либо попробовать написать несколько функций самостоятельно (например, напишите функцию для расчёта n-го числа из ряда Фибоначчи).</p>
<h2><strong>Общие использования рекурсии в XSL</strong></h2>
<p>Два общих сценария использования рекурсии в XSL такие:</p>
<ul>
<li>Когда у вас есть набор повторяющихся значений в исходном XML, и вы хотите, чтобы результат преобразования отражал что-то, касающееся всех этих значений. Например, если у вас есть каталог товаров в XML, и вы хотите представить эти товары в соответствии с общей ценой, вы захотите найти совокупную цену, используя рекурсивный шаблон.</li>
<li>Когда исходный XML содержит число <em>x</em> в теге, например &lt;countTo number="5"/&gt;, и вы хотите представить некоторую информацию <em>x</em> раз в результирующей выдаче. Факториал&nbsp;&mdash; типичный пример такого случая, но я рассмотрю более сложный пример немного позже.</li>
</ul>
<p>Я покажу рекурсивное решение, написанное на XSL для обоих сценариев, но сначала давайте взглянем на пример про факториал, решенный на XSL:</p>
<p><em>Распечатка 3. Решение задачи про факториал с использованием рекурсии на XSL</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;factorial&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;number&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;1&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:choose<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;$number &lt;= 1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;1&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;factorial&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;number&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$number - 1&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;$number * $recursive_result&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:choose<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Этот шаблон содержит все &laquo;игредиенты&raquo; из рецепта для Java-рекурсии. Здесь есть условие выхода (проверка на равенство единице или нет): если условие выхода не выполняется, шаблон делает рекурсивный вызов самого себя (хранимый в переменной <em>recursive_result</em>). Наконец, для получения конечного результата совершается операция умножения между исходным числом и рекурсивно полученным значением. Вы также могли заметить, что XSL частно требует намного больше кода, чем решение той же задачи в других языках. Это всего лишь часть неоднозначностей в языке преобразования, который согласовывается с XML.</p>
<h3><strong>Рекурсия, вариант 1: Суммирование сквозь множество элементов</strong></h3>
<p>Теперь вы можете применить такой же метод, как и в примере с факториалом из <em>Распечатки 3</em>, чтобы найти общую стоимость товаров в XML-каталоге. Фактически, решение аналогично решению задачи с факториалом, за исключением того, что вы будете использовать сложение вместо умножения и набор узлов как исходную информацию вместо числа.</p>
<p>Предположим, у вас есть каталог товаров, который выглядит походим на XML в <em>Распечатке 4</em> (кстати, вы можете скачать весь XML и XSL, и весь другой код из этой статьи по ссылке в <a href="http://www.ibm.com/developerworks/xml/library/x-xslrecur/#resources">Ресурсах</a>).</p>
<p><em>Распечатка 4. Пример XML с продуктами</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;Products<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;Product<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;Name<span class="re2">&gt;</span></span></span>Gadget<span class="sc3"><span class="re1">&lt;/Name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;Price<span class="re2">&gt;</span></span></span>$10.00<span class="sc3"><span class="re1">&lt;/Price<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/Product<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;Product<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;Name<span class="re2">&gt;</span></span></span>Gizmo<span class="sc3"><span class="re1">&lt;/Name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;Price<span class="re2">&gt;</span></span></span>$7.50<span class="sc3"><span class="re1">&lt;/Price<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/Product<span class="re2">&gt;</span></span></span><br />
&nbsp; ...<br />
&nbsp;<span class="sc3"><span class="re1">&lt;/Products<span class="re2">&gt;</span></span></span></div></div>
<p>Цель в том, чтобы добавить первую цену из этого списка товаров к сумме всех других цен, пока вы не получите суммарный результат. Вы можете осуществить это при помощи XSL, показанного в <em>Распечатке 5</em>.</p>
<p><em>Распечатка 5. Проход по узлам с использованием обычной XSL-рекурсии</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSum&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:choose<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;$productList&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSum&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &gt;</span></span> 1]&quot;/&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;number(substring-after($productList[1]/Price,'$'))</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;+ $recursive_result&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:otherwise<span class="re2">&gt;</span></span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;0&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:choose<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>В этом случае вы вызываете функцию на постепенно уменьшающемся списке товаров, каждый раз добавляя первый элемент в список к рекурсивному вызову на остальных элементах списка. Когда список получается пустым, условие выхода достигнуто и вы добавляете ноль к результату, что не изменит сумму. Этот метод работы на всё меньшем и меньшем наборе узлов может быть использован во многих случаях.</p>
<h3><strong>Рекурсия, вариант 2: Итерация на числе</strong></h3>
<p>Вторая задача, с которой сталкиваются XSL-программисты, возникает, когда число содержится в некоторых случаях в исходном XML, и программисту нужно решить задачу это число раз. Например, XML может выключать информацию о сетке с некоторыми числами строк и столбцов, и преобразование необходимое для обеспечения визуального расположения сетки в HTML или каком-либо другом формате.</p>
<p>Решение, как правило используемое разработчиками, незнакомыми с рекурсивными методами&nbsp;&mdash; это написать программу, которая разбирает XML и дополняет элементами для каждого ряда или столбца. Однажды написанный элемент &lt;xsl:for-each&gt; может решить задачу без рекурсивных шаблонов. Несмотря на то, что это решение обеспечивает подходящую выдачу, у него есть большой недостаток. Этот метод на самом деле удваивает объём работы для обеспечения финального результата преобразования. Этот недостаток чрезвычайно заметен в клиент-серверной модели, когда сервер посылает XML и XSL для преобразования на клиентской стороне. В таком случае всё продуктивности, обычно реализованные на сервере, теряются за счёт увеличения XML.</p>
<p>Лучшее решение&nbsp;&mdash; использовать рекурсивные шаблоны, чтобы выполнять работы полностью в рамках преобразования. Рассмотрим получение таблицы умножения из XML-элемента в виде HTML. Входная информация будет содержать следующую строку:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;MultiplicationTable</span> <span class="re0">Rows</span>=<span class="st0">&quot;3&quot;</span> <span class="re0">Columns</span>=<span class="st0">&quot;4&quot;</span><span class="re2">/&gt;</span></span></div></div>
<p>Цель состоит в том, чтобы преобразовать это в HTML, представляющий таблицу, похожую на:</p>
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<td></td>
<td><strong>1</strong></td>
<td><strong>2</strong></td>
<td><strong>3</strong></td>
<td><strong>4</strong></td>
</tr>
<tr>
<td><strong>1</strong></td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td><strong>2</strong></td>
<td>2</td>
<td>4</td>
<td>6</td>
<td>8</td>
</tr>
<tr>
<td><strong>3</strong></td>
<td>3</td>
<td>6</td>
<td>9</td>
<td>12</td>
</tr>
</table>
<p>Этот пример кое в чём более сложный, чем первые два. В этом случае вы не просто возвращаете функциональный результат, представляющий решение проблемы, но вы всего лишь выдадите HTML как шаг рекурсивного процесса. Также вам необходимо соединить вместе два рекурсивных шаблона&nbsp;&mdash; один для рядов, другой для столбцов.</p>
<p><em>Распечатка 6. Повторение по числу с использованием основной XSL-рекурсии</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;drawRow&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;currentRow&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;totalRows&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;totalCols&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:if</span> <span class="re0">test</span>=<span class="st0">&quot;$currentRow &lt;= $totalRows&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;tr<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;drawCell&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;currentRow&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$currentRow&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;currentCol&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;0&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;totalCols&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$totalCols&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;drawRow&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;currentRow&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$currentRow &nbsp;+ 1&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;totalRows&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$totalRows&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;totalCols&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$totalCols&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:if<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<br />
<span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;drawCell&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;currentRow&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;currentCol&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;totalCols&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:if</span> <span class="re0">test</span>=<span class="st0">&quot;$currentCol &lt;= $totalCols&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;bgColor&quot;</span><span class="re2">&gt;</span></span>...<span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;value&quot;</span><span class="re2">&gt;</span></span>...<span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;td</span> <span class="re0">bgcolor</span>=<span class="st0">&quot;{$bgColor}&quot;</span> <span class="re0">align</span>=<span class="st0">&quot;center&quot;</span> <span class="re0">valign</span>=<span class="st0">&quot;top&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;$value&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;drawCell&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;currentRow&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$currentRow&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;currentCol&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$currentCol + 1&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;totalCols&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$totalCols&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:if<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>В этом случае я использую два отдельный рекурсивных шаблона. Вначале рекурсивно рисую ряды пока не достигну условия выхода. Этот шаблон использует второй рекурсивный шаблон, чтобы нарисовать ячейки для каждого столбца в ряду. Этот общий метод применим для многоуровневого представления данных.</p>
<h2><strong>Оптимизация паттернов рекурсии в XSL</strong></h2>
<p>К сожалению, использование рекурсии во многих XSL-процессорах имеет один значительный недостаток при работе с большими объемами данных. Также слишком легко достигнуть переполнения стека (Stack Overflow) или нехватки памяти (Out of Memory) с функциями, которые достигают глубины порядка 10000. Если вы пытаетесь суммировать цены в каталоге с более чем 10000 товарами, вы можете столкнуться с проблемами.</p>
<p>К счастью, есть пути по оптимизации рекурсивных функций, чтобы уменьшить или даже исключить глубину рекурсии, вытекающую из заданного шаблона. Оставшаяся часть этой статьи представляет четыре способа оптимизировать то, как вы пишете ваши рекурсивные решения на XSL.</p>
<h3><strong>Оптимизация рекурсии 1. Разделяй и властвуй</strong></h3>
<p>Вспомните первый пример, в котором мы пытались найти общую цену, суммировав все цены для нескольких товаров в XML-каталоге. Первоначальный подход&nbsp;&mdash; это добавить цену первого товара к сумме всех остальных, и делать это рекурсивно, пока вы не переберёте весь лист. При использовании этого подхода глубина рекурсии равна числу товаров в списке. Сейчас цель состоит в том, чтобы изменить метод так, чтобы вы получили тот же результат без вхождения в рекурсию так глубоко.</p>
<p>Другой подход к этой проблеме&nbsp;&mdash; это разделить список на множество меньших частей и делать так рекурсивно, пока вы не разделите каждую часть на отдельные продукты. Самый простой путь представить это&nbsp;&mdash; разделение списка напополам, делая рекурсивный вызов на каждой половине и тогда сделать отдельные рекурсивные вызовы на двух получившихся списках. Это позволит завершить всю работу на одной половине,  до того как какая-то работа будет сделана на другой половине. Процесс обработки будет древовидный, а не линейный (похожий на лестницу) из первого решения. <em>Рисунок 2</em> показывает это рекурсивное дерево.<br />
<img src="http://www.ibm.com/developerworks/xml/library/x-xslrecur/tree.gif" alt="" /></p>
<p>Используя подход &laquo;разделяй и властвуй&raquo;, вы не ощутите никакой экономии, в цифрах, по числу операций сложения, которые должны быть выполнены. Экономия будет заключаться в том, что операции сложения не ожидают того, чтобы все числа были получены и поставлены в очередь в стек рекурсии для выполнения операции. XSL-код в <em>Распечатке 7</em> показывает такой способ.</p>
<p><em>Распечатка 7. Прохождение по узлам с использованием метода &laquo;разделяй и властвуй&raquo;</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumDivideAndConquer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:choose<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;count($productList) = 1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;number(substring-after($productList[1]/Price,'$'))&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;$productList&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;halfIndex&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;floor(count($productList) div 2)&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumDivideAndConquer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &amp;lt;= $halfIndex]&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result2&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumDivideAndConquer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &amp;gt; $halfIndex]&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;$recursive_result1 + $recursive_result2&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:otherwise<span class="re2">&gt;</span></span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;0&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:choose<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Операция сложения происходит каждый раз, когда разделённый список достигает длины 1 (это является условием выхода), и производится до того, как какая-нибудь обработка произойдёт со второй частью листа. При использовании этой техники глубина рекурсии никогда не превысит log<sub>2</sub> от количества элементов в списке, что, конечно, экспоненциально увеличивает возможное число товаров в списке для этого подсчёта.</p>
<h3><strong>Оптимизация рекурсии 2. Сегментация</strong></h3>
<p>Несмотря на невероятную экономию глубины рекурсии, обеспеченные методом &laquo;Разделяй и властвуй&raquo;, у него действительно есть недостатки. Для списков длиной не выражается числом степени двойки, этот способ излишне накладный на концах рекурсионного дерева.</p>
<p>Другой подход, который похоже уменьшает глубину рекурсии, работающий на итерациях через сегменты узлов предопределённой длины, предпочтительнее, чем деление узлов надвое каждый раз. Этот подход построен на базовой рекурсивной методике, но представлен внешним шаблоном, который действует как менеджер сегментации.</p>
<p>Роль менеджера сегментации состоит в том, чтобы разбить большую задачу на маленькие, которые могут быть проработаны без появления утечек памяти. Менеджер хранит результаты этих маленьких заданий и в тот момент, когда они все завершены, выполняет необходимую операцию над этими результатами.</p>
<p>Вы можете видеть пример техники Сегментации в шаблоне <em>Распечатки 8</em>, который берёт список узлов и длину сегмента и использует оригинальный шаблон для цен на этих маленьких частях.</p>
<p><em>Распечатка 8. Обход узлов с использованием техники сегментации</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumSegmented&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;segmentLength&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;5&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:choose<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;count($productList) &gt;</span></span> 0&quot;&gt;<br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSum&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &lt;= $segmentLength]&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result2&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumSegmented&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &gt;</span></span> $segmentLength]&quot;/&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;$recursive_result1 + $recursive_result2&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:otherwise<span class="re2">&gt;</span></span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;0&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:choose<span class="re2">&gt;</span></span></span> <br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Использование подхода Сегментации лучше, чем подхода &laquo;Разделяй и властвуй&raquo; уменьшает накладные расходы в большинстве случаев, но не предлагает особенной выгоды по глубине рекурсии. Какой же следует использовать? Ответ&nbsp;&mdash; как вы можете увидеть по следующей оптимизации&nbsp;&mdash; оба.</p>
<h3><strong>Оптимизация рекурсии 3. Сочетание Сегментации и &laquo;Разделяй и властвуй&raquo;</strong></h3>
<p>Вы можете объединить техники &laquo;Разделяй и властвуй&raquo; и Сегоментации, чтобы</p>
<ol>
<li>увеличить экномию за счёт снижения глубины рекурсии (включая накладную обработку, связанную<br />
с каждый добавлением уровня используемой рекурсии)</li>
<li>избежать накладных расходов на уровне листочков рекурсионного дерева</li>
</ol>
<p>В этом способе пороговый уровень передаётся в рекурсивный шаблон, через список узлов (или другие данные, которыми опрерируют). Здесь &laquo;Разделяй и властвуй&raquo; изменён, чтобы работать как менеджер сегментации. Если размер переданного списка больше, чем пороговое значение, список делится надвое и шаблон рекурсивно вызывается для обеих половин. Другими словами, вы используете основной рекурсивный шаблон, чтобы вычислять результаты, как и в Сегментации.<br />
<em>Распечатка 9</em> показывает этот способ на следующих XSL-шаблонах.</p>
<p><em>Распечатка 9. Обход узлов с использованием составной техники &laquo;Разделяй и властвуй&raquo; и Сегментации</em></p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumCombination&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;threshold&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;5&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:choose<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;count($productList) &gt;</span></span> $threshold&quot;&gt;<br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;halfIndex&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;floor(count($productList) div 2)&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumCombination&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &lt;= $halfIndex]&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;recursive_result2&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumCombination&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &gt;</span></span> $halfIndex]&quot;/&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:variable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;$recursive_result1 + $recursive_result2&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSum&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$productList&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:choose<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<h3><strong>Оптимизация рекурсии 4. Tail Recursion</strong></h3>
<p>У вас уже есть какой-то опыт по отношению к рекурсии и вы, возможно, удивлены, почему метод Tail Recursion не первый в способах оптимизации, с тех пор как этот способ может устранить глубокую рекурсию полностью без каких-либо накладных расходов. Несмотря на преимущества, которые этот способ предлагает, он требует, чтобы XSLT-процессор, производя эту трансформацию, распознавал присутствие этой техники в XSL-коде и изменял бы своё поведение для обеспечения этой техники. К сожалению, большинство XSL-процессоров не предлагают такую возможность.</p>
<p>Хорошая новость состоит в том, что непомерное одобрение XSL в бизнесе и научном мире означает, что это ограничение просуществует недолго. По этой причине для разработчиков важно понимать, как происходит отрубание хвоста, как оно может исключить проблемы с памятью без задерживания представления в любом достойном виде.</p>
<p>Основная идея Tail Recursion&nbsp;&mdash; это избавление от хранения какой-либо статической информации в рекурсивных шагах. Вся информация, которая нужна, на каждом шаге передаётся как параметры функции вместо того, чтобы храниться на более высоком уровне в стеке рекурсии. Это позволяет XSLT-процессору работать с рекурсивной функцией как с циклом в процедурном языке.</p>
<p>Взгляните на <em>Распечатку 1</em>0 примера с ценами с Tail Recursion.</p>
<p>Распечатка 10. Проход по узлам с использованием Tail Recursion</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumTail&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;result&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;0&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:choose<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:when</span> <span class="re0">test</span>=<span class="st0">&quot;$productList&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;priceSumTail&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;productList&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$productList[position() &gt;</span></span> 1]&quot;/&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;result&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">select</span>=<span class="st0">&quot;$result + </span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;number(substring-after($productList[1]/Price,'$'))&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:when<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:otherwise<span class="re2">&gt;</span></span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;$result&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/xsl:otherwise<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:choose<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Прибавление дополнительного значения переменной создаёт всю разницу. Вместо накомления чисел для сложения на разных рекурсивных шагах, сложение производится на каждом этапе и результат передаётся дальше как параметр для следующего шага рекурсии. Токовый XSLT-процессор просто перезаписывает участок памяти, содержащий значение переменной, при каждом вызове так же, как эта переменная перезаписывалась бы в случае Java или C кода. Этот способ позволяет языку пользоваться преимуществами и декларативных, и императивных языков без изменения сути XSLT как языка программирования.</p>
<h2><strong>Заключение</strong></h2>
<p>Как только вы поняли рекурсию, декларативный стиль программирования на XSLT будет не препятствием, а эффективным путем расширения возможностей преобразования XML. Остаётся единственный вопрос&nbsp;&mdash; какой тип рекурсии лучший для каждой отдельно взятой ситуации.</p>
<p>Вообще, задачи, работающие для малых объёмов данных, не требуют применения какой-либо из этих оптимизационных техник. Хотя, если малость объёма данных не гарантирована, выбор ограничен технологией, используемой в преобразовании. Если ваш XSLT-процессор распознаёт Tail Recursion, то лучше всего использовать этот способ. Если вы не можете убедиться, что преобразовательня технология умеет распознавать Tail Recursion, то наиболее предпочтительна комбинированная техника. Пороговое значение обычно лежит в диапазоне от 5 до 30 в зависимости от задачи.</p>
<p>Поначалу рекурсия может быть трудной для понимания идеей, но её полезность и элегантность становятся яснее по мере использования.</p>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/books-articles/xslt-articles/recursion.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>XSLT&#160;&#8212; результативные технологии программирования</title>
		<link>http://toivonen.ru/books-articles/xslt-articles/efficient_programming_techniques.html</link>
		<comments>http://toivonen.ru/books-articles/xslt-articles/efficient_programming_techniques.html#comments</comments>
		<pubDate>Sat, 25 Jul 2009 18:10:07 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Статьи об XSLT]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=168</guid>
		<description><![CDATA[ Перевод документа XSLT&#160;&#8212; Efficient Programming Techniques, который мне очень помог.
С ростом популярности XML как средства взаимодействия с различными системами, все больше и больше организаций приходят к XML, чтобы решить свои вопросы функциональной совместимости. Вместе с попытками архитекторов достигнуть ясного разделения между отображением и бизнес-логикой, XSLT становится важнее. XSL, по сути,&#160;&#8212; это XML-документ (дерево, согласно [...]]]></description>
			<content:encoded><![CDATA[<p> Перевод документа <a href="http://www.xml.org/sites/www.xml.org/files/xslt_efficient_programming_techniques.pdf">XSLT&nbsp;&mdash; Efficient Programming Techniques</a>, который мне очень помог.</p>
<p>С ростом популярности XML как средства взаимодействия с различными системами, все больше и больше организаций приходят к XML, чтобы решить свои вопросы функциональной совместимости. Вместе с попытками архитекторов достигнуть ясного разделения между отображением и бизнес-логикой, XSLT становится важнее. XSL, по сути,&nbsp;&mdash; это XML-документ (дерево, согласно спецификации DTD), который применяется к древовидным структурам данных (XML-документ), чтобы выработать результирующее дерево.<span id="more-168"></span></p>
<p>Эта статья представляет список лучших приемов, используемых для написания XSLT-преобразований. Эта статья может быть использована как направление к лучшему пути достижения нужных результатов в XSL. Она предназначается для разработчиков, которые знакомы с основами XSL, но нуждаются в указателе на действенный путь программирования на XSL. Информация в этой статье основана на моём собственном опыте в XML и XSL. Список лучших приемов составлен по различным источникам, чтобы сделать всеобъемлющий документ, который будет расти, если найдётся больше хороших приемов. Если у вас есть несколько очень хороших приёмов, которым вы следуете и которых нет в этом списке, скиньте мне на email <em>pboundre@gr.com</em>.</p>
<h2>Подключение внешних файлов&nbsp;&mdash; правильный путь</h2>
<p>Есть три способа включения внешних файлов в ваш xsl:</p>
<ol>
<li>Если у вас есть дополнительные HTML-файлы, которые вы хотите включить в ваш результат без изменений, возможно самый простой путь получить его в вашем результирующем дереве&nbsp;&mdash; это включить его как внешнюю синтаксическую сущность (entity) в преобразование. Это влечет за собой объявление сущности и обращение к ней в вашем преобразовании.
<p>header.html:</p>
<div class="codecolorer-container html4strict " style="overflow:auto;white-space:nowrap;width:auto"><div class="html4strict codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc2">&lt;<a href="http://december.com/html/4/element/table.html"><span class="kw2">table</span></a>&gt;</span><br />
&nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/tr.html"><span class="kw2">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">td</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span class="kw2">a</span></a> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/&quot;</span>&gt;</span>Home<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/a.html"><span class="kw2">a</span></a>&gt;&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">td</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">td</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span class="kw2">a</span></a> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/movies/&quot;</span>&gt;</span>Movies<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/a.html"><span class="kw2">a</span></a>&gt;&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">td</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">td</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span class="kw2">a</span></a> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/shop/&quot;</span>&gt;</span>Shop<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/a.html"><span class="kw2">a</span></a>&gt;&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">td</span></a>&gt;</span><br />
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/tr.html"><span class="kw2">tr</span></a>&gt;</span><br />
<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/table.html"><span class="kw2">table</span></a>&gt;</span></div></div>
<p>data.xsl:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc0">&lt;!DOCTYPE xsl:stylesheet [</span><br />
<span class="sc0">&lt;!-- declares header.html as an external parsed entity</span><br />
<span class="sc0">--&gt;</span><br />
<span class="sc3">&lt;!ENTITY header SYSTEM <span class="st0">&quot;header.html&quot;</span><span class="re2">&gt;</span></span><br />
]&gt;<br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span></span><br />
<span class="sc3"><span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>People<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc-1">&lt;!-- includes header.html directly --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc1">&amp;header;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
</li>
<li>У вас есть дополнительные XML-файле, которые вы хотели бы преобразовать и включить в документ, над которым вы работаете.<br />
Если у вас есть XML-файл, который вы хотели бы включить в результат, вам нужно использовать функцию document(), чтобы поучить доступ к информации, и вам нужны шаблоны в вашем преобразовании, чтобы обработать их и включить в результирующее дерево:</p>
<p>header.xml:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;menu<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item</span> <span class="re0">href</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span>Home<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item</span> <span class="re0">href</span>=<span class="st0">&quot;/movies/&quot;</span><span class="re2">&gt;</span></span>Movies<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item</span> <span class="re0">href</span>=<span class="st0">&quot;/shop/&quot;</span><span class="re2">&gt;</span></span>Shop<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/menu<span class="re2">&gt;</span></span></span></div></div>
<p>data.xsl:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span></span><br />
<span class="sc3"><span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>People<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc-1">&lt;!-- applies templates to the information contained in header.xml --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">select</span>=<span class="st0">&quot;document('header.xml')&quot;</span><span class="re2">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc-1">&lt;!-- applies templates to the input file --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="sc-1">&lt;!-- transforms the XML in header.xml into the table we want --&gt;</span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;menu&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;table<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;tr<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;item&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;{@href}&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span><span class="re1">&lt;/a<span class="re2">&gt;</span></span><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/table<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
</li>
<li>У вас есть внешние дополнительные XSLT-файлы, которые вы бы хотели использовать, чтобы формировать результирующее дерево:<br />
Пусть у вас есть входящий XML-документ, который включает включает некоторую информацию, нужную вам как и остальные данные на странице, вы захотите импортировать (import) или включить (include) преобразования для них, так чтобы шаблоны, определённые в них использовались будто они часть основного преобразования. То, что вам нужно: xsl:import или xsl:include&nbsp;&mdash; зависит от того, хотите ли вы переопределять шаблоны (или часть из них), которые заданы во включаемом преобразовании. Если хотите, используйте xsl:import, в противном случае&nbsp;&mdash; xsl:include.</p>
<p>data.xml</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;menu<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item</span> <span class="re0">href</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span>Home<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item</span> <span class="re0">href</span>=<span class="st0">&quot;/movies/&quot;</span><span class="re2">&gt;</span></span>Movies<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item</span> <span class="re0">href</span>=<span class="st0">&quot;/shop/&quot;</span><span class="re2">&gt;</span></span>Shop<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/menu<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;people<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;person</span> <span class="re0">age</span>=<span class="st0">&quot;50&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;larry&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;person</span> <span class="re0">age</span>=<span class="st0">&quot;50&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;larry&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/people<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span></div></div>
<p>header.xsl:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;menu&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;table<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;tr<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;item&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;{@href}&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span> <span class="re2">/&gt;</span><span class="re1">&lt;/a<span class="re2">&gt;</span></span><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/table<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
<p>data.xsl:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="re2">&gt;</span></span><br />
<span class="sc-1">&lt;!-- includes the templates from theheader.xsl stylesheet --&gt;</span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:include</span> <span class="re0">href</span>=<span class="st0">&quot;header.xsl&quot;</span> <span class="re2">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>People<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc-1">&lt;!-- applies templates to the menu definition to create the header - the templates come from header.xsl --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">select</span>=<span class="st0">&quot;doc/menu&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc-1">&lt;!-- applies templates to the data to create the rest of the document --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">select</span>=<span class="st0">&quot;doc/people&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; ...<br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
</li>
</ol>
<p>Вам также стоит иметь преобразование, включающее шаблоны для видоизменения информации в что-то, что вам нужно.</p>
<h2>Используйте XSL шаблоны проектирования (patterns)</h2>
<h3>Метод Кая для нахождения пересечения, разности и дизъюнкции множеств</h3>
<p>Единственная операция над множествами, предоставляемая XSLT,&nbsp;&mdash; это объединение. Оно может быть описано с использованием оператора объединения из XPath и XSLT&nbsp;&mdash; &laquo;|&raquo;. Можно выразить пересечение двух наборов узлов (node set) на чистом XPath. Этот способ был открыт Майклом Каем (Michael Kay) и известен как метод Кая (Kaysian method).</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;intersection&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$ns[count(.|$ns2) = count ($ns2)]&quot;</span><span class="re2">/&gt;</span></span><br />
<br />
<span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;set-difference&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;$ns1[count(.|$ns2) != count($ns2)]&quot;</span><span class="re2">/&gt;</span></span></div></div>
<p>Пример:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span> <span class="re0">xmlns:data</span>=<span class="st0">&quot;crane&quot;</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:output</span> <span class="re0">method</span>=<span class="st0">&quot;text&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;data:data<span class="re2">&gt;</span></span></span> <span class="sc-1">&lt;!--data source for testing purposes--&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>1<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>2<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>3<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>4<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>5<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>6<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/data:data<span class="re2">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span> <span class="sc-1">&lt;!--root rule--&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;ns1&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;//item[position()&gt;</span></span>1]&quot;/&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:variable</span> <span class="re0">name</span>=<span class="st0">&quot;ns2&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;//item[position()&amp;lt;5]&quot;</span><span class="re2">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;$ns1[count(.|$ns2)=count($ns2)]&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Intersection: <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;( $ns1[count(.|$ns2)!=count($ns2)] | $ns2[count(.|$ns1)!=count($ns1)] )&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Difference: <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
<p>Результат:</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">Intersection: 2<br />
Intersection: 3<br />
Intersection: 4<br />
Difference: 1<br />
Difference: 5<br />
Difference: 6</div></div>
<h3>Метод Вендела Пая для нерекурсивного цикла</h3>
<p>Метод Вендела Пая (Wendell Pie) демонстрирует способ избежать XSLT-рекурсии при применении циклов.</p>
<p>Пример:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;Tag</span> <span class="re0">ID</span>=<span class="st0">&quot;1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;Value<span class="re2">&gt;</span></span></span>4<span class="sc3"><span class="re1">&lt;/Value<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/Tag<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;Tag</span> <span class="re0">ID</span>=<span class="st0">&quot;2&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;Value<span class="re2">&gt;</span></span></span>2<span class="sc3"><span class="re1">&lt;/Value<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/Tag<span class="re2">&gt;</span></span></span></div></div>
<p>Требующийся результат:</p>
<div class="codecolorer-container html4strict " style="overflow:auto;white-space:nowrap;width:auto"><div class="html4strict codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc2">&lt;<a href="http://december.com/html/4/element/table.html"><span class="kw2">TABLE</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/tr.html"><span class="kw2">TR</span></a> <span class="kw3">ID</span><span class="sy0">=</span><span class="st0">&quot;1&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span> <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span> <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span> <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span> <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/tr.html"><span class="kw2">TR</span></a>&gt;</span><br />
<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/table.html"><span class="kw2">TABLE</span></a>&gt;</span><br />
<span class="sc2">&lt;<a href="http://december.com/html/4/element/table.html"><span class="kw2">TABLE</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/tr.html"><span class="kw2">TR</span></a> <span class="kw3">ID</span><span class="sy0">=</span><span class="st0">&quot;2&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span> <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span> <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/td.html"><span class="kw2">TD</span></a>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/tr.html"><span class="kw2">TR</span></a>&gt;</span><br />
<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/table.html"><span class="kw2">TABLE</span></a>&gt;</span></div></div>
<p>Другими словами, я хочу создать набор новых узлов, количество которых основано на значении Value, содержащемся в документе. Ниже я представляю маленькое обобщение,  которое не  зависит от числа узлов в исходном XML-документе и использует вместо этого число узлов в преобразовании:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;TAG&quot;</span><span class="re2">&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;TABLE<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;TR</span> <span class="re0">ID</span>=<span class="st0">&quot;@ID&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;(document('')//*)[position() &amp;lt;= Value]&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;TD<span class="re2">&gt;</span></span></span> <span class="sc3"><span class="re1">&lt;/TD<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/TR<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/TABLE<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Здесь используется количество элементов в преобразовании. Это количество будет значительно превышено, если мы будем проверять на разные типы узлов, например:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;($st//node()| $st//@* | $st//namespace::*) [position() &amp;ltt;= Value]&quot;</span><span class="re2">&gt;</span></span></div></div>
<p>где $st определено как  document(&#39;&#39;), то есть корневой узел преобразования.</p>
<h3>Метод условной выборки Оливера Беккера</h3>
<p>Воможность XPath выбирать список узлов, основываясь на сложных условиях, очень мощная. Хотя ей недостаёт возможностей для определения строки как противоположного набору узлов. Вам часто нужно использовать навороченную xsl:choose конструкцию только чтобы определить, что-то вроде &laquo;в случае 1 используй строку 1, в случае 2&nbsp;&mdash; строку 2, ..., в случае N&nbsp;&mdash; строку N.?</p>
<p>Во всех таких случаях нам нужен способ, который позволил бы нам определять в XPath-выражении строку, которая зависит от условия или условий.</p>
<p>Теперь о том, как это сделать:<br />
Мы хотим получить XPath-выражение, которое возвращает строку, когда некоторое заданное условие истинно, и возвращает пустую строку, если это условие ложно. Можно условиться, что true&nbsp;&mdash; это &bdquo;1&ldquo;, а false&nbsp;&mdash; это &bdquo;0&ldquo;. Но как подогнать &bdquo;1&ldquo; к какой-то строке? Какую функцию для работы со строкой мы могли бы использовать? <em>substring()</em> кажется достаточно удобной. А вот и трюк: мы можем использовать substring() только с двумя аргументами: substring(str, nOffset) возвратит остаток строки str, начинающийся с позиции nOffset.</p>
<p>В частности:<br />
<em>substring(str, 1)</em> возвращает целую строку<br />
<em>substring(str, [очень большое число])</em> возвратит пустую строку, если это большое число гарантированно больше, чем длина строки.</p>
<p>Таким образом, выражение, которое мы могли бы использовать, будет:</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">concat(<br />
&nbsp; &nbsp; substring( str1, exp( условие ) ),<br />
&nbsp; &nbsp; substring( str2, exp( not(условие) ) )<br />
)</div></div>
<p>и мы хотим, чтобы <em>exp(условие)</em> было 1, если условие истинное и Infinity, если условие ложное.</p>
<p>Мы выражаем exp(условие) так:<br />
<em>1 div условие</em>, потому что булево значение сначала преобразуется в число (true&nbsp;&mdash; в 1, а false&nbsp;&mdash; в 0), мы получим в точности:</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">exp(true) = 1<br />
exp(false) = Infinity</div></div>
<p>Итог:<br />
XPath-выражение, возвращающее одну строку, если условие истинно и другую, если оно ложно, такое:</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">concat(<br />
&nbsp; &nbsp; substring(Str1, 1 div условие),<br />
&nbsp; &nbsp; substring(Str2, 1 div условие)<br />
)</div></div>
<p>Впервые это было использовано Оливером Беккером (Oliver Becker) и названо как метод Беккера.</p>
<p>Например:<br />
Я хочу написать темплейт, который создаёт текст: &bdquo;My department&ldquo;,  если передан параметр &bdquo;IT&ldquo; и текст &bdquo;Some other department&ldquo;, если значение параметра другое.</p>
<p>Конечно, никаких xsl:if или xsl:when не допускается.</p>
<p>Пример кода:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span> <span class="re0">xmlns:data</span>=<span class="st0">&quot;crane&quot;</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">&gt;</span></span><br />
<br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:output</span> <span class="re0">method</span>=<span class="st0">&quot;text&quot;</span><span class="re2">/&gt;</span></span><br />
<br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; IT:<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;whoIs&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;department&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;'IT'&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;br</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; Finance:<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:call-template</span> <span class="re0">name</span>=<span class="st0">&quot;whoIs&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:with-param</span> <span class="re0">name</span>=<span class="st0">&quot;department&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;'Finance'&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:call-template<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">name</span>=<span class="st0">&quot;whoIs&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:param</span> <span class="re0">name</span>=<span class="st0">&quot;department&quot;</span> <span class="re0">select</span>=<span class="st0">&quot;someDepartment&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;br</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp;concat(</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp;substring('My department', 1 div ($department = 'IT')),</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp;substring('Some other department', 1 div not(($department = 'IT')))</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp;)&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;br</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
<h3>Используйте метод Мюнха для группировки</h3>
<p>Группировка часто плохо осуществляется в XSL. Обычно эта задача возникает, когда вы получаете XML-вывод (несгруппированный) из базы данных и должны сгруппировать его средствами XSL. База данных обычно выдаёт вам результаты, структурированные согласно записям в ней. Например, давайте рассмотрим таблицу служащих, из которой получается такой XML:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;data<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;employee</span> <span class="re0">no</span>=<span class="st0">&quot;1&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;name<span class="re2">&gt;</span></span></span>Prathit Bondre<span class="sc3"><span class="re1">&lt;/name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;department<span class="re2">&gt;</span></span></span>IT<span class="sc3"><span class="re1">&lt;/department<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/employee<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;employee</span> <span class="re0">no</span>=<span class="st0">&quot;2&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;name<span class="re2">&gt;</span></span></span>Adheet Bondre<span class="sc3"><span class="re1">&lt;/name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;department<span class="re2">&gt;</span></span></span>Finance<span class="sc3"><span class="re1">&lt;/department<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/employee<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;employee</span> <span class="re0">no</span>=<span class="st0">&quot;3&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;name<span class="re2">&gt;</span></span></span>Sinan Edil<span class="sc3"><span class="re1">&lt;/name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;department<span class="re2">&gt;</span></span></span>IT<span class="sc3"><span class="re1">&lt;/department<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/employee<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;employee</span> <span class="re0">no</span>=<span class="st0">&quot;4&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;name<span class="re2">&gt;</span></span></span>Jeremy King<span class="sc3"><span class="re1">&lt;/name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;department<span class="re2">&gt;</span></span></span>Finance<span class="sc3"><span class="re1">&lt;/department<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/employee<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/data<span class="re2">&gt;</span></span></span></div></div>
<p>Требуется такой вывод:<br />
<strong>Finance</strong><br />
Adheet Bondre<br />
Jeremy King</p>
<p><strong>IT</strong><br />
Prathit Bondre<br />
Sinan Edil</p>
<p>Задача состоит в том, чтобы превратить этот плоский вывод в список, сгруппированный по департаментам, чтобы дать требуемый результат, который показан выше.</p>
<p>Есть два шага на пути к решению:</p>
<ul>
<li>Узнать, какие департаменты существуют</li>
<li>Получить всех служащих, которые относятся к одному департаменту</li>
</ul>
<p>Узнать, какие департаменты существуют, можно выбрав по одному сотруднику из каждого департамента в XML, который может с успехом быть первым, кто попадётся. Один способ найти их&nbsp;&mdash; это взять тех сотрудников, которые не относятся к департаменту из множества департаментов предыдущих сотрудников.</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">employee[not(department = preceding-sibling::employee/department)]</div></div>
<p>Определив таких сотрудников, легко найти их департаменты и собрать вместе всех сотрудников из одного и того же департамента:</p>
<div class="codecolorer-container xsl " style="overflow:auto;white-space:nowrap;width:auto"><br /><strong>GeSHi Error:</strong> GeSHi could not find the language xsl (using path /home/w/wwsru/toivonen/public_html/wp-content/plugins/codecolorer/lib/geshi/) (code 2)<br /></div>
<p>Проблема этого метода в том, что он включает в себя два XPath-выражения, вычисление которых потребует много ресурсов для больших XML-документов. Поиск по всем предыдущим братьям с осью &#39;preceding-sibling&#39; занимает много времени, если вы ближе к конце записей. Кроме того, получение всех контактов определённых департаментов каждый раз включает в себя поиск одного сотрудника.</p>
<h4>Метод Мюнха</h4>
<p>Этот метод разработан Стивом Мюнхом (Steve Muench) для представления этих функций более эффективным способом с использованием ключей. Ключи работают путём назначения значения ключа узлу и дают прямой доступ к узлу через такое значение. Если элементов, у которых один и тот же ключ, много, то все эти элементы найдутся, когда вы воспользуетесь этим ключом. В сущности, это означает, что если вы хотите сгруппировать множество узлов согласно какому-то свойству узла, вы можете использовать ключи.</p>
<p>В примере выше мы хотим сгруппировать сотрудников согласно их департаментам, поэтому мы создаём ключ, который назначает каждому сотруднику значение ключа, которое берётся из департамента этого сотрудника. Узлы, которые мы хотим сгруппировать должны быть подставлены в атрибут &bdquo;match&ldquo;. Значение ключа, которые мы хотим использовать записывается в атрибут &bdquo;use&ldquo;.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:key</span> <span class="re0">name</span>=<span class="st0">&quot;employees-by-department&quot;</span> <span class="re0">match</span>=<span class="st0">&quot;employee&quot;</span> <span class="re0">use</span>=<span class="st0">&quot;department&quot;</span><span class="re2">/&gt;</span></span></div></div>
<p>Однажды определив ключ, зная департамент, мы можем быстро получить доступ ко всем сотрудникам этого департамента.<br />
Например, ключ <em>key(&#39;employees-by-department&#39;, &#39;IT&#39;)</em> даст записи с департаментом &bdquo;IT&ldquo;.</p>
<p>Однако, первое, что нам надо сделать,&nbsp;&mdash; это определить, какие бывают департаменты, что включает в себя нахождение первого сотрудника в XML для каждого департамента. Здесь мы снова можем использовать ключи. Мы знаем, что сотрудник будет частью списка узлов, которые можно получить по ключу данного департамента: вопрос в том, будет ли он первым в этом списке (который упорядочен как записи в XML-документе) или ниже? Нас интересуют только записи, идущие первыми в списке.<br />
Выяснение, является ли сотрудник первым в списке, возвращённом по ключу, подразумевает сравнение узла employee с первым узлом в списке. Этот способ также может быть использован для получения отдельных элементов в XML-файле. Есть пара характерных способов проверки, идентичны ли два узла:</p>
<ol>
<li>Сравнить уникальные идентификаторы, сгенерированные для узлов (используя <em>generate-id()</em>):
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">employee[generate-id() = generate-id(key('employees-by-department', department)[1])]</div></div>
</li>
<li>Посмотреть, сколько узлов включает в себя результат объединения двух узлов: один или два&nbsp;&mdash; узлы не могут повторяться во множестве, так что если там только один узел, то они должны быть одним и тем же узлом:
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">employee[count(.|key('employees-by-department', department)[1]) = 1]</div></div>
</li>
</ol>
<p>Однажды определив группы, вы можете отсортировать их так, как вам нравится. Также вы можете отсортировать узлы в рамках группы так, как вы хотите. Вот шаблон, который создаёт результат, который мы описали, из XML, полученного из базы данных:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto;height:300px"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:output</span> method = <span class="st0">&quot;html&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;Windows-1252&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:key</span> name = <span class="st0">&quot;employees-by-department&quot;</span> match =<span class="st0">&quot;employee&quot;</span> use = <span class="st0">&quot;department&quot;</span> <span class="re2">/&gt;</span></span><br />
<br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;data&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> select = <span class="st0">&quot;employee[count(.|key('employees-bydepartment',</span><br />
<span class="sc3">department)[1])=1]&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:sort</span> <span class="re0">select</span>=<span class="st0">&quot;department&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;b<span class="re2">&gt;</span></span><span class="re1">&lt;u<span class="re2">&gt;</span></span><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;department&quot;</span> <span class="re2">/&gt;</span><span class="re1">&lt;/u<span class="re2">&gt;</span></span><span class="re1">&lt;/b<span class="re2">&gt;</span></span><span class="re1">&lt;br</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:for-each</span> <span class="re0">select</span>=<span class="st0">&quot;key('employees-bydepartment',</span><br />
<span class="sc3">department)&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:sort</span> <span class="re0">select</span>=<span class="st0">&quot;name&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;name&quot;</span> <span class="re2">/&gt;</span><span class="re1">&lt;br</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:for-each<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
<p>Метод Мюнха обычно лучше использовать для группировки узлов из XML-документа, потому что он не подразумевает прохождения через большое число узлов, и поэтому он более эффективен. Он особенно полезен, когда у вас есть плоская выдача из базы данных, например, которую вам нужно преобразовать в какую-нибудь иерархичную структуру. Он может быть применён в любой ситуации, где нужно группировать узлы согласно их свойствам, которые можно получить через XPath.<br />
Обратная сторона состоит в том, что метод Мюнха будет работать только с XSLT-процессором, поддерживающим ключи. Вдобавок, использование ключей может быть достаточно затратным по памяти, потому что все узлы и их ключи хранятся в памяти. Наконец, может быть трудно использовать ключи, если узлы, которые вы хотите сгруппировать, получены из разных подключенных источников.</p>
<h2>Использование xsl:import</h2>
<p>Используйтер &lt;xsl:import&gt;, чтобы подключить общие, основные правила в преобразование, задуманное для определённых трансформаций. Если можете, не импортируйте больше шаблонов, чем вам нужно.</p>
<h2>Использование статического HTML</h2>
<p>Для любых &bdquo;неизменных&ldquo; порций html на странице (таких как шапка, подвал, элементы навигации) определённо более эффективно хранить фрагменты как внешние xml-файлы и копировать их в результирующее дерево используя xsl:copy-of и функцию document(), чем использовать именованные шаблоны или xsl:import.</p>
<h2>Разница между call и apply templates</h2>
<p>Call-template, в отличие от aplly-templates, не меняет контекстный (текущий) узел. И атрибут select имеет значение только в aplly-templates, и не имеет в call-template.</p>
<h2>Повторное использование кода и рефакторинг</h2>
<p>Проблема с использованием одного темплейта с множеством условий&nbsp;&mdash; это то, что очень быстро делает код отвратительным, нечитаемым и неподддерживаемым. Проблема многих шаблонов состоит в том, что вы часто дублируете код. Золотая середина&nbsp;&mdash; использовать много шаблонов, а при необходимости повторить код&nbsp;&mdash; вызывать именованные шаблоны, иногда с параметрами, если имеют место небольшие изменения, которые должны быть учтены. Именованные шаблоны похожи на подпрограммы или приватные методы.</p>
<p>Например. Допустим, вы хотите обработать элементы item, имея один шаблон для узлов со значением атрибута type&nbsp;&mdash; &#39;Book&#39;, один&nbsp;&mdash; для &#39;CD&#39;, и один для всех остальных.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;item[@type='Book']&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;item[@type='CD']&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;item&quot;</span><span class="re2">/&gt;</span></span></div></div>
<p>И они переопределят шаблон, привязанный к &bdquo;*&ldquo; (любой элемент). Шаблоны с более точной адресацией будут иметь более высокий приоритет для сопоставления.</p>
<h2>Автоматизируйте XSL-документацию</h2>
<p>Программисты обычно ненавидят документацию и поэтому обычно не пишут её. Javadocs в Java даёт большое утешение программистскому сообществу, обеспечивая способ автоматически генерировать документацию. Есть похожий инструмент, который написан для XSL и называется xsldoc. Его можно бесплатно скачать на <a href="http://www.xsldoc.org/">www.xsldoc.org</a>.<br />
Этот инструмент обеспечит автоматизированный, стандартизированный и надежный способ создания документации о ваших XSL-файлах, и поскольку он управляется из командной строки, то может стать частью процесса сборки.</p>
<h2>Не изобретайте велосипед, используйте XSLT-библиотеку</h2>
<p>XSLT-библиотека&nbsp;&mdash; это open source репозиторий XSL-шаблонов, которые были написаны и проверены. В библиотеке множество шаблонов для работы со строками, датами, обработки узлов и т.п., что может быть эффективно использовано в ваших xsl-файлах. Так что сэкономьте своё время с этой библиотекой. Её можно посмотреть по адресу <a href="http://xsltsl.sourceforge.net">http://xsltsl.sourceforge.net</a>.</p>
<h2>Уменьшайте размер ваших HTML-документов</h2>
<p>Уменьшайте размер вашего HTML, используя <em>indent=&raquo;no"</em> в теге &lt;xsl:output/&gt;. Этот атрибут сообщает XSLT-процессору не делать отступы в HTML-документе, что делает файлы меньше и они грузятся быстрее.</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:output</span> <span class="re0">method</span>=<span class="st0">&quot;html&quot;</span> <span class="re0">indent</span>=<span class="st0">&quot;no&quot;</span><span class="re2">/&gt;</span></span></div></div>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/books-articles/xslt-articles/efficient_programming_techniques.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Глава 2. Неизменный &#171;Hello, world&#187;</title>
		<link>http://toivonen.ru/books-articles/xslt-by-orelly/hello_world_example/introduction/obligatory-hello-world.html</link>
		<comments>http://toivonen.ru/books-articles/xslt-by-orelly/hello_world_example/introduction/obligatory-hello-world.html#comments</comments>
		<pubDate>Mon, 13 Jul 2009 12:40:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Первое преобразование, введение]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=155</guid>
		<description><![CDATA[ Сначала напомню, что это перевод глав из книги &#171;XSLT&#187; издательсва O&#39;Reilly.
В следующих главах мы потратим много времени на XSLT, XPath и различные продвинутые функции, используемые для преобразования XML-документов. Сначала, несмотря ни на что, мы погрузимся в короткий пример, чтобы проиллюстрировать, как работают преобразования.
2.1. Цели этой главы
К концу этой главы вы будете знать:

Как создать основной [...]]]></description>
			<content:encoded><![CDATA[<p> Сначала напомню, что это перевод глав из книги &laquo;XSLT&raquo; издательсва O&#39;Reilly.<br />
В следующих главах мы потратим много времени на XSLT, XPath и различные продвинутые функции, используемые для преобразования XML-документов. Сначала, несмотря ни на что, мы погрузимся в короткий пример, чтобы проиллюстрировать, как работают преобразования.<span id="more-155"></span></p>
<h2>2.1. Цели этой главы</h2>
<p>К концу этой главы вы будете знать:</p>
<ul>
<li>Как создать основной шаблон</li>
<li>Как использовать шаблон для преобразования XML-длкумента</li>
<li>Как XSLT-процессор использует шаблон для преобразования документа</li>
<li>Структуру XSLT-шаблона</li>
</ul>
<h2>2.2 Преобразование &laquo;Hello, world&raquo;</h2>
<p>Продолжая традицию примера &laquo;Hello, world&raquo;, начатую Брайаном Керниганом (Brian Kernighan) и Денисом Ритчи (Dennis Ritchie) в кгиге &laquo;Язык программирования C&raquo; (The C Programming Language (Prentice Hall, 1988), мы будем преобразовывать &laquo;Hello, world&raquo; XML-документ.</p>
<h3>2.2.1 Наш пример документа</h3>
<p>Сначала мы посмотрим на наш пример документа. Это простой XML-документ, учитывающий XML-спецификацию версии 1.0, включающий в себя знаменитое дружественное приветствие к миру:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;greeting<span class="re2">&gt;</span></span></span><br />
Hello, World!<br />
<span class="sc3"><span class="re1">&lt;/greeting<span class="re2">&gt;</span></span></span></div></div>
<p>Что мы бы хотели, так это преобразовать этот обворожительный документ в что-то, что мы могли бы видеть в обычном браузере.</p>
<h3>2.2.2 Пример шаблона</h3>
<p>Это XSLT-шаблон, который определяет, как преобразовать XML-документ:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:stylesheet</span></span><br />
<span class="sc3"> &nbsp; &nbsp;<span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp;<span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:output</span> <span class="re0">method</span>=<span class="st0">&quot;html&quot;</span><span class="re2">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">select</span>=<span class="st0">&quot;greeting&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;greeting&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
<p>Мы поговорим об этих элементах и том, что они делают через минуту. Имейте в виду, что шаблон сам по себе XML-документ, так что мы должны следовать всем правилам XML-документа, которые мы обсудили в предыдущей главе.</p>
<h3>2.2.3 Преобразование XML-документа</h3>
<p>Чтобы преобразовать XML-документ, используя XSLT-шаблон, запустите эту команду:</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">java org.apache.xalan.xslt.Process -in greeting.xml -xsl greeting.xsl -out greeting.html</div></div>
<p>Эта команда преобразует документ <em>greeting.xml</em>, используя шаблоны, найденные в файле <em>greeting.xsl</em>. Результаты преобразования записываются в файл <em>greeeting.html</em>. Проверьте получившийся файл в вашем любимом браузере, чтобы удостовериться, что преобразование работает верно.</p>
<h3>2.2.4 Результаты преобразования</h3>
<p>XSLT-процессор свормировал следующие результаты:</p>
<div class="codecolorer-container html4strict " style="overflow:auto;white-space:nowrap;width:auto"><div class="html4strict codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc2">&lt;<a href="http://december.com/html/4/element/html.html"><span class="kw2">html</span></a>&gt;</span><br />
<span class="sc2">&lt;<a href="http://december.com/html/4/element/body.html"><span class="kw2">body</span></a>&gt;</span><br />
<span class="sc2">&lt;<a href="http://december.com/html/4/element/h1.html"><span class="kw2">h1</span></a>&gt;</span><br />
Hello, World!<br />
<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/h1.html"><span class="kw2">h1</span></a>&gt;</span><br />
<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/body.html"><span class="kw2">body</span></a>&gt;</span><br />
<span class="sc2">&lt;<span class="sy0">/</span><a href="http://december.com/html/4/element/html.html"><span class="kw2">html</span></a>&gt;</span></div></div>
<p>После отрисовки в браузере, получившийся документ выглядит так:<br />
<img src="http://img-fotki.yandex.ru/get/3510/toivonens.0/0_26fe3_334e865e_L.jpg" width="386" height="116" title="" alt="" border="0"/></p>
<p>Поздравляю! Вы только что использовали XSLT для преобразования XML-документа.</p>
<h2>2.3 Как обрабатываются шаблоны</h2>
<p>Сейчас пока у нас кружится голова от волнения, потому что мы смогли преобразовать XML-документ, давайте обсудим шаблоны и то, как они работают. Большая часть изучения хитростей XSLT&nbsp;&mdash; постигать, как обрабатываются шаблоны. Чтобы было яснее, мы будем продвигаться по шагам, диктуемым шаблоном XSLT-процессору для создания HTML-документа, который мы хотим.</p>
<h3>2.3.1 Разбор шаблона</h3>
<p>До того как XSLT-процессор сможет обработать ваш шаблон, ему нужно прочесть его. По большому счету не имеет значения, как XSLT-процессор считывает информацию из вашего шаблона. Для наших целей, мы будем только притворяться, что XSLT-процессор может волшебным образом находить всё, что ему нужно, в нашем файле. (Если вам действительно нужно знать, Xalan использует оптимизированную табличную структуру для представления шаблона; другие процессоры могут использовать этот подход или что-то другое.)</p>
<p>Наше преобразование включает три вещи: элемент &lt;xsl:output>, который определяет HTML в качестве выходного формата и два элемента &lt;xsl:template>, которые определяют, как части нашего XML-документа будут преобразованы.</p>
<p>2.3.2 Разбор преобразуемого<br />
Сейчас, чтобы XSLT-процессор обработал шаблон, ему нужно прочесть документ, который предполагается преобразовать. XSLT-процессор строит представление в виде дерева, исходя из XML-кода. Это тот самый вид, который мы имели в виду, когда создавали наш шаблон.</p>
<h3>2.3.3 Намылить, прополоскать, повторить</h3>
<p>Наконец, мы готовы начать саму работу преобразований XML-документа. XSLT-процессор может определить несколько свойств, основываясь на вашем преобразовании (в первом примере это было определение метода вывода как HTML), тогда он начнёт обработку следующим образом:</p>
<ul>
<li>У меня есть какие-нибудь узлы для обработки? Узлы, предназначающиеся для обработки представлены как контекст (context). Вначале контекстом является корень XML-документа, но он изменяется по ходу преобразования. Мы поговорим о контексте более подробно в следующей главе.</li>
</ul>
<p>Пока в контексте есть какие-либо узлы, делается следующее:</p>
<ul>
<li>Получаю следующий узел из контекста. Есть ли у меня какой-нибудь шаблон &lt;xsl:template>, чтобы сопоставить с ним? (в нашем примере следующий узел в корневом элементе, представленным в XPath синтаксическим выражением &laquo;/&raquo;.) Шаблон, которые соответствует узлу&nbsp;&mdash; это что-то, начинающееся с &lt;xsl:template match="/">.</li>
<li>Если один или более шаблонов &lt;xsl:template> подходят, беру нужный и обрабатываю его. (Нужный&nbsp;&mdash; это наиболее уточнённый шаблон. Например, &lt;xsl:template match="/html/body/h1/p"> более точен, чем &lt;xsl:template match="p">.) Если подходящих шаблонов нет, XSLT-процессор использует некоторые встроенные правила. Об этом позже.</li>
</ul>
<p>Заметим, что это рекурсивная модель обработки. Мы обрабатываем текущий узел, находя подходящий шаблон xsl:template для него. Этот шаблон xsl:template может в свою очередь вызывать другие шаблоны xsl:template, которые вызывают следующие. Эта модель вырабатывается привычкой, и пока к ней привыкать.</p>
<p>Если поможет, вы можете думать о корневом элементе (&lt;xsl:template match="/">) как о методе main в C, C++ и Java. Не имеет значения, сколько кода вы написали, всё начинается с main. Также не имеет значения, сколько шаблонов &lt;xsl:template> вы определили в своём преобразовании, всё начинается с &lt;xsl:template match="/">.</p>
<h3>2.3.4 Прогулка по нашему примеру</h3>
<p>Давайте мысленно возвратимся к нашему примеру и посмотрим, как XSLT-процессор преобразует документ:</p>
<ol>
<li>XSLT-пеобразование разбирается и превращается в древовидную структуру</li>
<li>XML-документ также разбирается и превращается в древовидную структуру. (Не слишком беспокойтесь о том, на что похожа древовидная структура и как это работает; пока достаточно помнить, что XSLT-процессор знает всё о том, что есть в XML-документе и XSLT-преобразовании.)</li>
<li>XSLT-процессор сейчас на корневом элементе. Это исходный контекст.</li>
<li>Есть шаблон xsl:template, который подходит корню документа:
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:apply-templates</span> <span class="re0">select</span>=<span class="st0">&quot;greeting&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
Один обратный слеш (/) в XPath выражении означает &laquo;корень документа&raquo;.</li>
<li>Сейчас обработка началась снова внутри шаблона xsl:template. Наша единственная инструкция здесь&nbsp;&mdash; применить какой-либо шаблон, могущий быть примененным к некоторому элементу greeting в текущем контексте. Текущий контексте в рамках этого шаблона определяется значением атрибута match элемента xsl:template. Это означает, что XSLT-процессор ищет какие-либо элементы greeting и шаблон xsl:template, что применить второй шаблон из нашего преобразования:
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;greeting&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsl:value-of</span> <span class="re0">select</span>=<span class="st0">&quot;.&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
</li>
<li>Сейчас мы в шаблоне xsl:template для элемента greeting. Первые три элемента в этом шаблоне (&lt;html>, &lt;body> и &lt;h1>)&nbsp;&mdash; это HTML-элементы. Поскольку они не определены в декларации пространств имён, XSLT-процессор прогоняет эти HTML-элементы через  выходной поток неизменными.</li>
<li>В середине нашего шаблона есть элемент xsl:value-of. Этот элемент выводит значение чего-либо в выходной поток. В этом случае, мы использует XPath выражение . (одиночная точка), чтобы определить текущий узел. XSLT-процессор смотрит на текущий узел (элемент greeting, который мы сейчас обрабатываем) и выводит его текст.<br />
Поскольку наше преобразование&nbsp;&mdash; это XML-документ (мы постоянно твердим об этом, так?), мы должны закрыть теги &lt;h1>, &lt;body>, и &lt;html>. На этой стадии мы закончили с этим шаблоном, так что контроль возвращается к шаблону, который вызвал нас.
</li>
<li>Сейчас мы вернулись в шаблон для корневого элемента. Мы обработали всё greeting элементы, так что мы закончили с этим шаблоном.</li>
<li>В текущем контексте больше нет никаких элементов (существует только один корневой элемет), так что XSLT-преобразование закончено.<br />
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/books-articles/xslt-by-orelly/hello_world_example/introduction/obligatory-hello-world.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Шаблон &#171;Hello, world!&#187;</title>
		<link>http://toivonen.ru/notes/master_class/xslt_hello_world.html</link>
		<comments>http://toivonen.ru/notes/master_class/xslt_hello_world.html#comments</comments>
		<pubDate>Sun, 12 Jul 2009 19:25:48 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Мастер класс]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=148</guid>
		<description><![CDATA[ Первый написанный XSLT-шаблоны&#160;&#8212; это страница, выводящая надпись &#171;Hello, world!&#187;. Для работы с кодом используем программу IntelliJIDEA.  В блоге Вадима Макишвили о работе с ней рассказано достаточно подробно.
Свой первый шаблон мы ассоциируем с главной страницей. Каждая страница в нашем проекте представляется отдельным xml-файлом (сейчас&#160;&#8212; статическим, но в последствии они будут генерироваться на сервере). &#171;Рыба&#187; [...]]]></description>
			<content:encoded><![CDATA[<p> Первый написанный XSLT-шаблоны&nbsp;&mdash; это страница, выводящая надпись &laquo;Hello, world!&raquo;. Для работы с кодом используем программу IntelliJIDEA.  В <a href="http://makishvili.com/tag/intellijidea/">блоге Вадима Макишвили</a> о работе с ней рассказано достаточно подробно.</p>
<p>Свой первый шаблон мы ассоциируем с главной страницей.<span id="more-148"></span> Каждая страница в нашем проекте представляется отдельным xml-файлом (сейчас&nbsp;&mdash; статическим, но в последствии они будут генерироваться на сервере). &laquo;Рыба&raquo; выглядит так:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;utf-8&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;?xml-stylesheet</span> <span class="re0">type</span>=<span class="st0">&quot;text/xsl&quot;</span> <span class="re0">href</span>=<span class="st0">&quot;../index.xsl&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;page</span> <span class="re0">name</span>=<span class="st0">&quot;index&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc-1">&lt;!-- Содержание страницы --&gt;</span><br />
<span class="sc3"><span class="re1">&lt;/page<span class="re2">&gt;</span></span></span></div></div>
<p>Вся информация заключена в корневой тег page, у которого есть атрибут name. Этот атрибут можно использовать для уточнения шаблонов конкретных страниц.<br />
Как видно из процессорной инструкции в &laquo;рыбе&raquo;, каждую страницу мы собираемся ассоциировать с одноимённым XSL-файлом. Поскольку мы используем XSLT-процессор, поддерживающий процессорные инструкции, то мы можем переопределять шаблоны для отдельных страниц в тех файлах, которые соответствуют этим страницам. Если же необходимо одним и тем же образом преопределить шаблон для нескольких страниц, можно написать общий переопределяющий шаблон, используя в предикате значения атрибута name.</p>
<p>Чтобы написать XSLT-преобразование для этой страницы, нужно создать файл index.xsl. Содержание файла поначалу следующее:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;utf-8&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;xsl:stylesheet</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">xmlns:xsl</span>=<span class="st0">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc-1">&lt;!-- Здесь будет преобразование --&gt;</span><br />
<span class="sc3"><span class="re1">&lt;/xsl:stylesheet<span class="re2">&gt;</span></span></span></div></div>
<p>XSL-шаблоны записываются в виде XML-файлов, поэтому для них действуют те же правила, что и для любых других XML-документов. Файл начинается с XML-декларации (первая строка). Всё теги заключены в один корневой тег xsl:stylesheet. Поскольку используется пространство имён (namespace) xsl, оно объявлено в корневом теге.</p>
<p>Для того, чтобы после наложения XSLT получился бы вывод какой-либо информации, необходимо написать шаблон (template). Начнём с шаблона на корневой узел page:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/page&quot;</span><span class="re2">&gt;</span></span>Hello, world!<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Этот код необходимо поместить в файл index.xsl в тег xsl:stylesheet. Запись match="/page" означает, что процессор применит перечисленные в шаблоне инструкции с корневому элементу с именем &laquo;page&raquo;. То, что это должен быть именно корневой элемент, говорит знак слеш перед его именем.<br />
Значение атрибута match&nbsp;&mdash; это XPath&nbsp;&mdash; путь, описывающий положение узла (или узлов) в документе. <a href="http://zvon.org/xxl/XPathTutorial/General/examples.html">Об XPath можно почитать на zvon.org</a>.</p>
<p>Предложенный шаблон выводит вместо корневого тега page то, что у него внутри. То есть надпись &laquo;Hello, world!&raquo;<br />
Более осмысленные шаблоны мы будем писать в следующий раз. Это будут шаблоны для формы авторизации и приветствия авторизованного пользователя.</p>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/notes/master_class/xslt_hello_world.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Сайт на XSL. Подготовка</title>
		<link>http://toivonen.ru/notes/master_class/xslt-site-preparing.html</link>
		<comments>http://toivonen.ru/notes/master_class/xslt-site-preparing.html#comments</comments>
		<pubDate>Sat, 11 Jul 2009 18:03:39 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Мастер класс]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=134</guid>
		<description><![CDATA[ Итак, мы делаем сайт и учим XSLT.
Сайт у нас будет на тему &#171;календарь менструального цикла&#187;, потому что мы типа профессионалы, и для нас нет запретных тем.
Движок на PHP, а шаблоны на XSLT. Их я и буду описывать.
Для того, чтобы всё заработало, нам потребовалось установить модуль под Apache для выполнения XSLT-преобразований. Мы выбрали xslt_filter. Однако, [...]]]></description>
			<content:encoded><![CDATA[<p> Итак, мы делаем сайт и учим XSLT.<br />
Сайт у нас будет на тему &laquo;календарь менструального цикла&raquo;, потому что мы типа профессионалы, и для нас нет запретных тем.<br />
Движок на PHP, а шаблоны на XSLT. Их я и буду описывать.<span id="more-134"></span><br />
Для того, чтобы всё заработало, нам потребовалось установить модуль под Apache для выполнения XSLT-преобразований. Мы выбрали <a href="http://xslt-filter.deviurg.com/">xslt_filter</a>. Однако, выяснилось, что скомпилированный из предложенных исходников модуль не работает с EXSLT-функциями.<br />
Сначала мы убедились, что EXSLT-функции есть в нашей библиотеке libxslt. Для этого в консоли нужно написать</p>
<div class="codecolorer-container text " style="overflow:auto;white-space:nowrap;width:auto"><div class="text codecolorer" style="font-family:Monaco,Lucida Console,monospace">xsltproc --dumpextensions</div></div>
<p>Эта команда выводит список расширений, доступных в libxslt. Нужные нам EXSLT-функции были. Но xslt_filter с ними не работал. О том, как зарегистрировать функции мы узнали <a href="http://osdir.com/ml/gnome.lib.xslt/2002-06/msg00062.html">по этой ссылке</a>. После перекомпиляции всё стало как надо.</p>
<p>Теперь мы можем писать свои шаблоны. Первые из них будут для отображения формы авторизации и вывода новостей сайта. Со всеми подробностями&nbsp;&mdash; в следующем сообщении.</p>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/notes/master_class/xslt-site-preparing.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Простые числа и XPath</title>
		<link>http://toivonen.ru/notes/problems/prime-numbers-xpath.html</link>
		<comments>http://toivonen.ru/notes/problems/prime-numbers-xpath.html#comments</comments>
		<pubDate>Sun, 21 Jun 2009 16:40:54 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Задачи]]></category>

		<category><![CDATA[xml/xsl]]></category>

		<category><![CDATA[xpath]]></category>

		<guid isPermaLink="false">http://toivonen.ru/?p=128</guid>
		<description><![CDATA[ Иногда мы на работе решаем интересные задачки. Вот, например, одна (почти первая) в постановке nop`а:
Частный случай:
Дан такой xml:
&#60;items&#62;
&#160; &#160;&#60;item&#62;1&#60;/item&#62;
&#160; &#160;&#60;item&#62;2&#60;/item&#62;
&#160; &#160;...
&#160; &#160;&#60;item&#62;N-1&#60;/item&#62;
&#160; &#160;&#60;item&#62;N&#60;/item&#62;
&#60;/items&#62;
т.е. выписаны все натуральные числа от 1 до N включительно. Про N ничего заранее не известно&#160;&#8212;
большое, маленькое, еще какое-то&#160;&#8212; мы не знаем. 
Нужно. Написать xpath, выбирающий все item&#39;ы с простыми числами.
Подчеркиваю&#160;&#8212; xpath.
Т.е. [...]]]></description>
			<content:encoded><![CDATA[<p> Иногда мы на работе решаем интересные задачки. Вот, например, одна (почти первая) в постановке <a href="http://alpha-san.ya.ru/"><span style="color: #000000;"><strong><span style="color: #ff0000;">n</span>op`а</strong></span></a>:</p>
<p><strong>Частный случай:</strong><br />
Дан такой xml:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;items<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>1<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>2<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>N-1<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>N<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/items<span class="re2">&gt;</span></span></span></div></div>
<p>т.е. выписаны все натуральные числа от 1 до N включительно. Про N ничего заранее не известно&nbsp;&mdash;<br />
большое, маленькое, еще какое-то&nbsp;&mdash; мы не знаем. </p>
<p>Нужно. Написать <strong>xpath</strong>, выбирающий все item&#39;ы с простыми числами.<br />
Подчеркиваю&nbsp;&mdash; <strong>xpath</strong>.<span id="more-128"></span><br />
Т.е. внутри тега xsl:stylesheet должен быть один примерно такой шаблон:</p>
<div class="codecolorer-container xslt " style="overflow:auto;white-space:nowrap;width:auto"><div class="xslt codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;xsl:copy-of</span> <span class="re0">select</span>=<span class="st0">&quot;.......&quot;</span><span class="re2">/&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>и больше ничего&nbsp;&mdash; ни переменных, ни других шаблонов, ни функций.</p>
<p>На выходе будет что-то типа:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>2<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>3<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>5<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>7<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
...</div></div>
<p>Решение следующее:</p>
<div class="codecolorer-container xslt " style="overflow:auto;white-space:nowrap;width:auto"><div class="xslt codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;items<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;xsl:copy-of</span> <span class="re0">select</span>=<span class="st0">&quot;items/item[not(preceding-sibling::item[(last() + 1) mod . = 0 and . != 1]) and . != 1]&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;/items<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p><strong>Общая задача</strong><br />
Усложненный вариант&nbsp;&mdash; все тоже самое, но в xml просто набор item&#39;ов с какими-то натуральными числами<br />
в каком-то порядке, например:</p>
<div class="codecolorer-container xml " style="overflow:auto;white-space:nowrap;width:auto"><div class="xml codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;items<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>142<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>73<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>10000341<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;item<span class="re2">&gt;</span></span></span>10<span class="sc3"><span class="re1">&lt;/item<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp;...<br />
<span class="sc3"><span class="re1">&lt;/items<span class="re2">&gt;</span></span></span></div></div>
<p>Решение:</p>
<div class="codecolorer-container xslt " style="overflow:auto;white-space:nowrap;width:auto"><div class="xslt codecolorer" style="font-family:Monaco,Lucida Console,monospace"><span class="sc3"><span class="re1">&lt;xsl:template</span> <span class="re0">match</span>=<span class="st0">&quot;/&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;items<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;xsl:copy-of</span> <span class="re0">select</span>=<span class="st0">&quot;items/item[not(</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; str:tokenize(str:padding(. - 1, '1'), '')[(last() + 1 ) mod position()= 0 and position() != 1]</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; and . != 1]&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;/items<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/xsl:template<span class="re2">&gt;</span></span></span></div></div>
<p>Чтобы понять, что тут делается, надо прочитать про функции <a href="http://exslt.org/str/functions/padding/index.html">padding</a> и <a href="http://exslt.org/str/functions/tokenize/index.html">tokenize</a> на EXSLT.org.</p>
]]></content:encoded>
			<wfw:commentRss>http://toivonen.ru/notes/problems/prime-numbers-xpath.html/feed</wfw:commentRss>
		</item>
	</channel>
</rss>

