РАЗНЫЕ МЕЛОЧИ В XSL

Разное

<img src="{dir}{image_large}" alt="{name}" width="{image_large_width}" height="{image_large_height}" /> 
<xsl:variable name="var_compare_id" select="."/>
<xsl:text disable-output-escaping="yes" select="."> </xsl:text>
<xsl:text> </xsl:text>
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='short_name']/value" />
<xsl:if test="description !=''">
  <xsl:value-of disable-output-escaping="yes" select="description" />
</xsl:if>
<xsl:if test="position() mod 3 = 0 and position() != last()">
  <xsl:text disable-output-escaping="yes">
  &lt;/tr&gt;
  &lt;tr valign="top"&gt;
  </xsl:text>
</xsl:if>

<xsl:if test="property_value[tag_name='link']/value !=''">
   <xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='link']/value" />
</xsl:if>

Дополнительное свойство - ссылка

property_value[tag_name='link']/value !=''

<xsl:if test="property_value[tag_name='link']/value !=''">
   <xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='link']/value" />
</xsl:if>

<xsl:if test="property_value[tag_name='link']/value !=''">
<a href="{property_value[tag_name='link']/value}" target="_parent" >
  <img src="{dir}{image_small}" alt="{name}"/>
</a>
</xsl:if>

<xsl:if test="property_value[tag_name='short_name']/value !=''">
   <xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='short_name']/value" />
</xsl:if>

Дополнительное свойство - изображение

<xsl:if test="property_value[tag_name='img']/file !=''">
<a href="{property_value[tag_name='img']/file}">
  <img src="{dir}{property_value[tag_name='img']/file}" alt="{name}"
width="{property_value[tag_name='img']/file_width}" height="{property_value[tag_name='img']/file_height}"/>
</a>
</xsl:if>

Ограничение количества групп в выпадающем меню

<!-- Если есть подгруппы -->
<xsl:if test="count(shop_group) > 0 and 1 > count(ancestor::shop_group)">
<ul class="left_menu gray_link gray" id="{@id}" style="display: none;">
<xsl:apply-templates select="shop_group"/>
</ul>
</xsl:if>

Выбираем последний элемент списка и назначаем ему класс last

<xsl:if test="position() mod 4 = 0 and position() > 3">
<xsl:attribute name="class">last</xsl:attribute>
</xsl:if>

Выбираем первый элемент списка и назначаем ему класс first

<xsl:if test="position() mod 1 = 0 and position() < 2">
<xsl:attribute name="class">first</xsl:attribute>
</xsl:if>

Ссылка на все товары производителя в карточке товара

<xsl:if test="shop_producer/node()">
<xsl:variable name="shop_produser_id" select="shop_producer/@id" />
<a href="{/shop/url}producer-{$shop_produser_id}" class="button">Другие товары этого производителя</a>
</xsl:if>

Ограничиваем текст по количеству знаков

<xsl:variable name="myConcatString" select="description"/>
<xsl:value-of disable-output-escaping="yes" select="substring($myConcatString, 1, 800)" /><xsl:text>...</xsl:text>

Вставляем код JAVASCRIPT в XSL

<SCRIPT>
<xsl:comment>
<xsl:text disable-output-escaping="yes">
<![CDATA[
.........код скрипта......................
]]>
</xsl:text>
</xsl:comment>
</SCRIPT>        

Шаблон для условия

      <xsl:choose>
<xsl:when test="">
...
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>

Если нет изображения, то скрываем блок на boostrap 5

<div class="d-none">
<xsl:if test="image_small != ''">
<xsl:attribute name="class">col-xs-3 col-sm-3 col-md-3 col-lg-3</xsl:attribute>
</xsl:if>
<xsl:if test="image_small != ''">
<div>
<a href="{url}">
<img src="{dir}{image_small}" alt="{name}"/>
</a>
</div>
</xsl:if>

Меняем адрес ссылки, если есть Дополнительное свойство - Ссылка на материал

<xsl:variable name="link">
<xsl:choose>
<xsl:when test="property_value[tag_name='link']/value !=''">
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='link']/value" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="url" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="property_value[tag_name='link']/value !=''">
<a href="{property_value[tag_name='link']/value}" >
<img src="{dir}{image_small}" class="news_img" alt="" />
</a>
</xsl:when>
<xsl:otherwise>
<img src="{dir}{image_small}" class="news_img" alt="" />
</xsl:otherwise>
</xsl:choose>

Определяем позицию
Добавляем атрибут

<xsl:attribute name="class">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">right</xsl:when>
<xsl:otherwise>left</xsl:otherwise>
</xsl:choose>
</xsl:attribute>

Последний элемент строки

<xsl:if test="position() = last()">
<xsl:attribute name="style">background-image: none</xsl:attribute>
</xsl:if>
<xsl:if test="position() = last()">
<xsl:attribute name="class">last</xsl:attribute>
</xsl:if>

Для меню

<xsl:variable name="position">
<xsl:choose>
<xsl:when test="$count div position() <= 1">4</xsl:when>
<xsl:otherwise>3</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="position() mod $floor = 0 and position() != last()">
<xsl:text disable-output-escaping="yes">
</ul>
<ul>
</xsl:text>
</xsl:if>

Перевод строки после n-элемента

<xsl:if test="position() mod 4 = 0 and position() != last()">
<xsl:text disable-output-escaping="yes">
</ul>
<ul class="shop_table">
</xsl:text>
</xsl:if>
<xsl:if test="position() mod 3 = 0 and position() != last()">
<span class="table_row"></span>
</xsl:if>
<xsl:if test="position() mod 3 = 0 and position() != last()">
<xsl:attribute name="style">background-image: none</xsl:attribute>
</xsl:if>

В списках

<!-- Перевод строки после каждого 2-го элемента -->
<xsl:if test="((position() - 2) mod 2 = 0) and position() != last()">
<xsl:text disable-output-escaping="yes">
</div>
<div class="wrapper">
</xsl:text>
</xsl:if>

В таблице

<xsl:template match="shop_item">
<td>
.............
</td>
<xsl:if test="position() mod 3 = 0">
<xsl:text disable-output-escaping="yes"></tr><tr></xsl:text>
</xsl:if>
</xsl:template>
<div id="gallery" class="board" style="max-width: {$image_width + 50}px">

Вывод сообщение "В данном разделе магазина товаров нет", если раздел пустой

<xsl:if test="count(shop_item) = 0 and .//shop_group[@id=$group]/items_total_count = 0" >В данном разделе
товаров нет</xsl:if>

Вставляем значение дополнительного свойства в ссылку для изображения

<!-- Изображение для информационного элемента (если есть) -->
<xsl:choose>
<xsl:when test="property_value[tag_name='url']/value != ''">
<a href="{property_value[tag_name = 'url']/value}" target="_parent">
<img src="{dir}{image_small}" align="left"/>
</a>
</xsl:when>
<xsl:otherwise>
<img src="{dir}{image_small}" align="left"/>
</xsl:otherwise>
</xsl:choose>

Выводим массив дополнительных свойств - изображения (file)

<xsl:if test="property_value[tag_name='img']/file != ''">
<ul>
<xsl:for-each select="property_value[tag_name='img']">
<li><a href="{../dir}{file}" ><img src="{../dir}{file_small}" alt="{name}" /></a></li>
</xsl:for-each>
</ul>
</xsl:if>
<xsl:for-each select="property_value[tag_name='dopfoto']">
<a href="{../dir}{file}" target="_blank"><img src="{../dir}{file_small}" /></a>
</xsl:for-each>

Вставляем дату и время в XSL шаблон 

<dt>
<xsl:value-of select="substring-before(date, '.')"/>
<xsl:variable name="month_year" select="substring-after(date, '.')"/>
<xsl:variable name="month" select="substring-before($month_year, '.')"/>
<xsl:choose>
<xsl:when test="$month = 1"> января </xsl:when>
<xsl:when test="$month = 2"> февраля </xsl:when>
<xsl:when test="$month = 3"> марта </xsl:when>
<xsl:when test="$month = 4"> апреля </xsl:when>
<xsl:when test="$month = 5"> мая </xsl:when>
<xsl:when test="$month = 6"> июня </xsl:when>
<xsl:when test="$month = 7"> июля </xsl:when>
<xsl:when test="$month = 8"> августа </xsl:when>
<xsl:when test="$month = 9"> сентября </xsl:when>
<xsl:when test="$month = 10"> октября </xsl:when>
<xsl:when test="$month = 11"> ноября </xsl:when>
<xsl:otherwise> декабря </xsl:otherwise>
</xsl:choose>
<xsl:value-of select="substring-after($month_year, '.')"/><xsl:text> г.</xsl:text>
</dt>

Заменяем запятую на точку в цене (каталог товаров)

В самом начале шаблона вывода товаров определяем формат вывода
имеется 

<xsl:decimal-format name="my" decimal-separator="," grouping-separator=" "/>
добавляем
<xsl:decimal-format name="my1" decimal-separator="." grouping-separator=" "/>

в выводе цены вставляем код

<xsl:value-of select="format-number(price, '### ##0.00', 'my1')"/>

Откладываем в корзину минимальное количество товара по умолчанию

1. Создаем Допсвойство "Минимальное количество" min_quantity, тип строка.
  В карточке товара в Допсвойстве "Минимальное количество" указываем минимальное количество для заказа, например, 10шт.

2. В XSL-шаблоне "ИнтернетМагазинКаталогТоваров" или "ИнтернетМагазинТовар" создаем переменную quantum, которая из Допсвойства min_quantity выделяет только числа

  

3. Вставляем значение переменной $quantum в скрипт кнопки "В корзину"

ПРИМЕР
<div class="actions">
<xsl:variable name="string" select="property_value[tag_name='min_quantity']/value"/>
<!-- Выделяем из строки числа -->
<xsl:variable name="quantum" select="translate($string, translate($string,'0123456789,',''),'')" />
<a data-animation="fadeAndPop" data-reveal-id="modalCart" id="add_to_cart_{@id}" href="#">
<button class="button btn-cart" onclick="return $.bootstrapAddIntoCart('{/shop/url}cart/', {@id}, {$quantum}); yaCounter31644173.reachGoal('addtocart'); return true;" title="В корзину" type="button">
<i class="fa fa-shopping-cart bg-color5">
<b></b>
</i>
<span class="bg-color3"><span>В корзину</span></span>
</button>
</a>
</div>

Обработка даты - приведение к числу для последующего сравнения с другой датой

<xsl:variable name="datetime" select="datetime" />
<xsl:value-of select="concat(substring($datetime, 7, 4), substring($datetime, 4, 2), substring($datetime, 1, 2), substring($datetime, 12, 2), substring($datetime, 15, 2), substring($datetime, 18, 2) )" disable-output-escaping="yes" />

Пересобираем URL (удаление первых трех символов)


<xsl:variable name="url">
<xsl:for-each select="url">
<xsl:variable name="link">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:value-of select='substring($link, 4, string-length($link) - 1)'/>
</xsl:for-each>
</xsl:variable>
<a href="/en{$url}">... </a>

Меняем формат вывода даты


<div class="date">
<xsl:variable name="month_year" select="substring-after(date, '.')"/>
<xsl:variable name="month" select="substring-before($month_year, '.')"/>
<xsl:variable name="time1" select="substring-after(datetime, ' ')"/>
<xsl:variable name="time2" select="substring-after($time1, ':')"/>
<xsl:variable name="hour" select="substring-before($time1, ':')"/>
<xsl:variable name="minutes" select="substring-before($time2, ':')"/>
<span><xsl:value-of select="substring-before(date, '.')"/>.<xsl:value-of select="$month"/> / <xsl:value-of select="$hour"/>:<xsl:value-of select="$minutes"/></span>
</div>

СОРТИРОВКА ТОВАРОВ ОТ МИНИМАЛЬНОЙ ЦЕНЫ ПО УМОЛЧАНИЮ



В XSL-шаблоне МагазинКаталогТоваров заменяем код          
<!--===== Выводим товары магазина =====-->
<div class="row products-grid">
<xsl:apply-templates select="shop_item"/>
</div>
на этот
<!--===== Выводим товары магазина =====-->
<div class="row products-grid">
<xsl:apply-templates select="shop_item">
<xsl:sort select="price" order="ascending" data-type="number"/>
</xsl:apply-templates>
</div>
 
Для сортировки товаров по умолчанию от максимальной цены заменить ascending на descending
Сортировка Допсвойств по id 
<xsl:apply-templates select="property_value[not(file/node())]">
<xsl:sort select="property_id" order="ascending" data-type="number"/>
</xsl:apply-templates>

Случайный вывод элементов


<xsl:template match="/">
<xsl:for-each select="shop_item">
<xsl:value-of select="generate-id()"/> <br/>
</xsl:for-each>
</xsl:template>

Выводим надпись "НОВИНКА" для товаров, загруженных за последние 30 дней


<xsl:variable name="сurrent_date" select="/shop/сurrent_date"/>
<xsl:variable name="date" select="translate(date, translate(date, '0123456789', ''), '')"/>
<xsl:variable name="difference_date" select="$сurrent_date - $date" />
<xsl:if test="number($difference_date) < 30">
<div class="ribbon-wrapper-new">НОВИНКА</div>
</xsl:if>

Предварительно добавляем в ТДС Интернет-магазина вывод текущей даты
Текущая дата в Каталоге товаров

Меняем высоту блока, в зависимости от размера файла изображения из Допсвойства


<div id="sub-menu" class="dropdown-menu">

<xsl:if test="property_value[tag_name='img']/file !=''">
<xsl:attribute name="style">height:<xsl:value-of disable-output-escaping="yes" select="20+(property_value[tag_name='img']/file/@height)" />px</xsl:attribute>
// добавляем к высоте картинки 20px, если нужно, изменить параметр
</xsl:if>
.........
</div>
XSL

Вывод брендов с разбивкой по алфавиту

XSL шаблон, который выводит бренды из модуля интернет-магазина, разделяя их по алфавиту
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:hostcms="http://www.hostcms.ru/"
	exclude-result-prefixes="hostcms">
	<xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="utf-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml"/>
	
	<xsl:key name="a" match="shop_producer" use="substring(name, 1, 1)" />
	
	
	<!-- МагазинСписокПроизводителей -->
	
	<xsl:template match="/">
		<section id="produsers">
			<xsl:apply-templates select="shop"/>
		</section>
	</xsl:template>
	
	<xsl:template match="shop">
		
		<div class="top">
			<h1>Бренды</h1>
		</div>
		
		<xsl:if test="count(shop_producer) = 0">
			<div id="error">Производители не найдены!</div>
		</xsl:if>
		
		<div class="block3" style="padding: 5px 0 12px 5px;">
			<div class="row">
				<ul>
					<xsl:apply-templates select="shop_producer" mode="alphabet">
						<xsl:sort select="name" order="ascending"/>
					</xsl:apply-templates>
				</ul>
			</div>
			
			<!--xsl:apply-templates select="shop_producer">
			<xsl:sort select="name" order="ascending"/>
		</xsl:apply-templates-->
	</div>
</xsl:template>

<xsl:template match="shop_producer" mode="alphabet">
	<xsl:variable name="a" select="substring(name,1,1)"/>
	<xsl:if test="not(preceding-sibling::shop_producer[starts-with(name, $a)][1])">
		<li class="col-xs-12">
			<h4><xsl:value-of select="$a"/></h4>
			
			<div class="row">
				<ul>
					<xsl:for-each select="/shop/shop_producer">
						<xsl:variable name="name" select="substring(name,1,1)"/>
						<xsl:if test="$a = $name">
						<li class="col-xs-6 col-sm-4 col-md-3 match-height"><a class="producer" href="{/shop/url}producer-{@id}/"><xsl:value-of disable-output-escaping="no" select="name"/></a></li>
						</xsl:if>
					</xsl:for-each>
				</ul>
			</div>
		</li>
	</xsl:if>
</xsl:template>

<xsl:template match="shop_producer">
	<a class="producer" href="{/shop/url}producers/{path}/"><xsl:value-of disable-output-escaping="no" select="name"/></a>
</xsl:template>

</xsl:stylesheet>
XSL

Интернационализация в XSL-шаблонах

В HostCMS интернационализация XSL-шаблонов осуществляется с использованием сущностей. Часто используемы внешние данные могут быть предварительно объявлены как сущности, а затем использованы в XSL-шаблоне.
Такое решение позволяет использовать один и тот же XSL-шаблон на разных сайтах, работающих на разных языках.
Для каждого языка, используемого на сайтах системы, автоматически создается отдельный DTD, который доступен при редактировании XSL-шаблона. Язык указывается в разделе "Сайты" в двухбуквенном формате ISO 639-1. Добавление сайта с новым языком автоматически добавляет для него DTD.
Подключение соответствующего языку DTD происходит автоматически, для этого в XSL-шаблоне вместо
<!DOCTYPE xsl:stylesheet>
указывается
<!DOCTYPE xsl:stylesheet SYSTEM "lang://21">
где 21 - идентификатор XSL-шаблона. Кроме идентификатора XSL-шаблона допускается использованием названия XSL-шаблона в случае его написания на английском языке, например, для XSL-шаблона с названием Search:
<!DOCTYPE xsl:stylesheet SYSTEM "lang://Search">
Объявление сущностей в DTD
Например, объявление сущности labelSearch:
<!ENTITY labelSearch "Поиск">
позволяет в дальнейшем использовать ее в XSL-шаблоне:
<h1>&labelSearch;</h1>
или в атрибутах
<img src="/images/my-image.png" alt="&labelSearch;" title="&labelSearch;" />
Ручное изменение используемого языка
Изменение языка подключаемого DTD возможно явным вызовом метода Core::setLng(), передав ему двухбуквенный код языка. Вызов необходимо делать перед использованием XSL, например, в начале макета.
Core::setLng('en');
Добавление DTD для языков, которые не указаны у сайтов
Вы можете добавить в конфигурационный файл modules/xsl/config/config.php дополнительные языки, для которых требуется создание DTD:

<?php
return array (
'lngs' => array('en', 'de', 'ru'),
);
XSL

Наиболее часто используемые XSLT и XPath функции

Функции XSLT

  • node-set current() — возвращает текущий узел преобразования;
  • node-set document(object, node-set) — позволяет обращаться к внешним документам по заданным URI. Первый узел необязательного параметра node-set принимается за точку отсчета для относительных URI;
  • boolean element-available(string) — проверяет доступность элемента или множества, указанного в параметре. В качестве параметра принимает строку - имя искомого элемента;
  • string format-number(number, format, name?) — возвращает число number в виде строки, отформатированной в соответствии с параметром format. Необязательный параметр name - это имя QName, задающее формат в соответствии правилами элемента <xsl:decimal-format>;
  • boolean function-available(string) — проверяет доступность функции указанной в параметре. В качестве параметра принимает строку - имя функции;
  • string generate-id(node-set) — присваивает уникальный строковый идентификатор первому узлу переданного множества node-set или контекстного узла, если аргумент опущен;
  • node-set key(name, value) — по данному имени name и значению ключа value возвращает множество узлов, которые им обладают. Ключи создаются при помощи элемента <xsl:key>;
  • string system-property(string)— возвращает значения системных свойств, имя которых передается как аргумент;
    • xsl:version — возвращает версию XSLT процессора;
    • xsl:vendor — возвращает производителя XSLT процессора;
    • xsl:vendor-url — возвращает URL, идентифицирующий производителя.
  • string unparsed-entity-uri(string) — предоставляет доступ к не разбираемым сущностям, возвращая URI сущности по ее имени.

Функции XPath

Логические функции

  • boolean boolean(object)— функция возвращает логическое значение переданного ей объекта;
    • number — если число равно нулю возвращает ложь, иначе — истину. NaN всегда возвращает ложь;
    • string — если строка не пуста возвращает истину, иначе — ложь;
    • boolean — значение не изменяется;
    • node-set — пустой набор узлов дает ложь, иначе — истину.
  • boolean false() — функция возвращает ложь;
  • boolean lang(string) — функция проверяет соответствие языка контекстного узла(определенного параметром xml:lang) переданному ей языку в виде строки string;
  • boolean not(boolean) — выполняет логическое отрицание;
  • boolean true() — функция возвращает истину.

Числовые функции

  • number ceiling(number) — округляет аргумент до ближайшего целого, не меньшего переданного функции числа;
  • number floor(number) — округляет аргумент до ближайшего целого, не большего переданного функции числа;
  • number number(object?) — явным образом приводит переданный функции объект в числовой тип. Если аргумент опущен, то применяется к множеству контекстного узла;
  • number round(number) — округляет аргумент до ближайшего целого значения;
  • number sum(node-set) — суммирует значения узлов переданного ей множества.

Строковые функции

  • string concat(string, string, …) — возвращает конкатенацию аргументов;
  • boolean contains(string, string) — принимает на вход два строковых аргумента и возвращает true, если первая строка содержит вторую и false в противном случае;
  • string normalize-space(string?) — удаляет начальные и завершающие разделительные символы, нормализует все внутренние идущие подряд разделители в один пробел. Если аргумент опущен, выполняется со строковым значением контекстного узла;
  • boolean starts-with(string, string) — принимает на вход два строковых аргумента и проверяет начинается ли первая строка со второй;
  • string string(object?) — приводит объект к строковому типу явным образом. Если аргумент опущен, то применяется к множеству контекстного узла;
  • number string-length(string?) — возвращает длину переданного ей строкового аргумента. Если аргумент опущен, то применяется к контекстному узлу;
  • string substring(string, number, number?) — возвращает подстроку переданного ей строкового аргумента, начинающуюся с позиции определенной вторым аргументом и длиной, указанной третьим аргументом. Если третий аргумент не передан, то подстрока продолжается до конца строки;
  • string substring-after(string, string) — принимает на вход два строковых аргумента, находит в первой строке вторую и возвращает подстроку, которая за ней следует;
  • string substring-before(string, string) — принимает на вход два строковых аргумента, находит в первой строке вторую и возвращает подстроку, которая ей предшествует;
  • string translate(string, string, string) — производит замену символов первого своего строкового аргумента, которые присутствуют во втором аргументе на соответствующие символы третьего аргумента.

Функции для работы с наборами узлов

  • number count(node-set) — возвращает число узлов в наборе node-set, переданного ей в качестве аргумента;
  • node-set id(id-value) — возвращает множество узлов по уникальным идентификаторам;
  • number last() — возвращает позицию последнего узла в наборе узлов;
  • string local-name(node-set?) — возвращает локальное (неполное) имя узла, или имя первого узла множества. Если node-set не передан, функция вернет имя контекстного узла;
  • string name(node-set?) — возвращает полное имя узла, или имя первого узла множества. Если node-set не передан, функция вернет локальную часть имени контекстного узла;
  • string namespace-uri(node-set?) — возвращает URI пространства имен а расширенном имени узла;
  • number position() — возвращает позицию контекстного узла в наборе узлов.xsl
XSL

Сортировка значений дополнительных свойств

Значения дополнительных свойств выбираются из нескольких таблиц и не имеют порядка сортировки, в отличии от самих дополнительных свойств. Если Вам необходимо выводить значения дополнительных свойств в порядке сортировки свойств, то в XSL-шаблоне необходимо вместо прямого применения шаблона к property_value применять шаблон к property, а из шаблона property применять шаблон к property_value с ограничением по property_id.

Вариант 1

<xsl:template match="shop_item">
    ...
        <xsl:apply-templates select="/shop/shop_item_properties//property">
                         <xsl:sort
                                                        select = "sorting"
                                                        data-type = "number"
                                                        order = "ascending"
                                        />
        </xsl:apply-templates>
    ...
 </xsl:template>

<xsl:template match="property">
       <xsl:variable name="property_id" select="@id" />
       <xsl:if test="/shop/shop_item/property_value[property_id = $property_id]/value/node() and /shop/shop_item/property_value[property_id = $property_id]/value != '' or /shop/shop_item/property_value[property_id = $property_id]/type != 2">
          <tr>
             <td><xsl:value-of disable-output-escaping="yes" select="name"/></td>
             <xsl:apply-templates select="/shop/shop_item/property_value[property_id = $property_id]" />
          </tr>
       </xsl:if>
 </xsl:template>

<xsl:template match="/shop/shop_item/property_value">
       <xsl:variable name="property_id" select="property_id" />
       <xsl:variable name="property" select="/shop/shop_item_properties//property[@id=$property_id]" />
       
       <td style="padding: 5px" bgcolor="#F5F5F5">
          <xsl:choose>
             <xsl:when test="$property/type = 7">
                <input type="checkbox" disabled="disabled">
                   <xsl:if test="value = 1">
                      <xsl:attribute name="checked">checked</xsl:attribute>
                   </xsl:if>
                </input>
             </xsl:when>
             <xsl:otherwise>
                <xsl:value-of disable-output-escaping="yes" select="value"/>
             </xsl:otherwise>
          </xsl:choose>
       </td>
 </xsl:template>

Рабочий вариант с сайта (вывод свойств разбит по директориям)

			<xsl:if test="count(property_value[property_dir_id=14])">
												<div class="property_list_title">Габариты и вес</div>
												<div class="propertys-property_list">
													<xsl:apply-templates select="/shop/shop_item_properties//property[property_dir_id=14]">
													    <xsl:sort
                                                        select = "sorting"
                                                        data-type = "number"
                                                        order = "ascending"
                                                    />
                                                    </xsl:apply-templates>
												</div>
			</xsl:if>
<xsl:template match="property">
           <xsl:variable name="property_id" select="@id" />
       <xsl:if test="/shop/shop_item/property_value[property_id = $property_id]/value/node() and /shop/shop_item/property_value[property_id = $property_id]/value != '' or /shop/shop_item/property_value[property_id = $property_id]/type != 2">

            <xsl:apply-templates select="/shop/shop_item/property_value[property_id = $property_id]" mode="property_list"/>
         
       </xsl:if>
 </xsl:template>
	<!-- Вывод строки со значением свойства -->
	<xsl:template match="property_value" mode="property_list">
			<xsl:f test="value/node() and value != '' or file/node() and file != ''">
					<div class="shop_property">
								<xsl:variable name="property_id" select="property_id" />
								<xsl:variable name="property" select="/shop/shop_item_properties//property[@id=$property_id]" />

								<span class="property-name">
									<xsl:value-of select="$property/name"/>
								</span>
								<span class="property-value"><xsl:choose>
										<xsl:when test="$property/type = 2">
											<a href="{../dir}{file}" target="_blank"><xsl:value-of select="file_name"/></a>
										</xsl:when>
										<xsl:when test="$property/type = 5">
											<a href="{informationsystem_item/url}"><xsl:value-of select="informationsystem_item/name"/></a>
										</xsl:when>
										<xsl:when test="$property/type = 7">
											<input type="checkbox" disabled="disabled">
												<xsl:if test="value = 1">
													<xsl:attribute name="checked">checked</xsl:attribute>
												</xsl:if>
											</input>
										</xsl:when>
										<xsl:when test="$property/type = 12">
											<a href="{shop_item/url}"><xsl:value-of select="shop_item/name"/></a>
										</xsl:when>
										<xsl:otherwise>
											<xsl:value-of disable-output-escaping="yes" select="value"/>
											<!-- Единица измерения свойства -->
											<xsl:if test="$property/shop_measure/node()">
												<xsl:text> </xsl:text><xsl:value-of select="$property/shop_measure/name"/>
											</xsl:if>
										</xsl:otherwise>
								</xsl:choose></span>
					</div>
			</xsl:if>
	</xsl:template>

Вариант 2


   <!-- Шаблон для товара -->
    <xsl:template match="shop_item">
       ...
          <xsl:variable name="myItem" select="." />
          
          <xsl:for-each select="/shop/shop_item_properties//property">
             <xsl:variable name="propertyId" select="@id" />
             <xsl:choose>
             <xsl:when test="count($myItem/property_value[property_id = $propertyId])">
                <xsl:apply-templates select="$myItem/property_value[property_id = $propertyId]"/>
             </xsl:when>
             <xsl:otherwise><td></td></xsl:otherwise>
             </xsl:choose>
          </xsl:for-each>
      ...
    </xsl:template>

Вариант 3

Используется при сортировке значений дополнительных свойств при выводе списка товаров. Хук вносится в код типовых динамических страниц и добавляет тег sort для значений доп. свойств (в примере для значений свойств целого и строчного типа).

Не путайте добавляемый тег sort с тегом sorting, в котором указывается внутренний порядок сортировки множественных значений свойства.
if (!$Shop_Controller_Show->item)
{
    class Property_Value_Observer
    {
        static public function onBeforeGetXml($object, $args)
        {
            $object->addXmlTag('sort', $object->Property->sorting);
        }
    }

    Core_Event::attach('property_value_string.onBeforeGetXml', array('Property_Value_Observer', 'onBeforeGetXml'));
    Core_Event::attach('property_value_int.onBeforeGetXml', array('Property_Value_Observer', 'onBeforeGetXml'));    
}

Вариант 4

Сортировка значений одного свойства в порядке добавления достигается указанием <xsl:sort select="@id" />, например:

<xsl:for-each select="property_value[tag_name='img'][file !='']">
    <xsl:sort select="@id" />
    <div class="item">
        <a href="{../dir}{file}" class="elevatezoom-gallery" data-image="{../dir}{file}" data-zoom-image="{../dir}{file}">
            <img class="img-responsive" height="150" width="100" src="{../dir}{file}"/>
        </a>
    </div>
</xsl:for-each>

XSL

ШАБЛОН "МагазинСамыеПопулярныеТовары"

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:hostcms="http://www.hostcms.ru/" exclude-result-prefixes="hostcms">
     <xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="UTF-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml"/>

     <!-- Шаблон показа популярных товаров.
     Основан на шаблоне "МагазинКаталогТоваровНаГлавнойСпецПред" -->

     <!-- Кол-во товаров в строку
     Если указано 0 то не разбивать, выводить все в одну строку -->
     <xsl:param name="items_per_line" select="'3'"/>

     <!--Формат вывода чисел-->
     <xsl:decimal-format name="my" decimal-separator="," grouping-separator=" "/>

     <!--Создадим ключ по идентификатору товара, чтобы оптимизировать выборку товаров при показе в предопределенном порядке -->
     <xsl:key name="items_id" match="/shop/shop_item" use="@id"/>

     <!--Признак того, что нужно показывать товары в порядке убывания популярности-->
     <xsl:variable name="is_ordered_show" select="/shop/popular/method = 'orders' and /shop/popular/item"/>


     <xsl:template match="/shop">
          <!-- Есть товары -->
          <xsl:if test="shop_item">
               <h1>Популярные товары</h1>

               <!-- Выводим товары магазина -->
               <xsl:choose>

                    <!--Если в XML существуют узлы, описывающие порядок показа товаров-->
                    <xsl:when test="$is_ordered_show">

                         <!--то запустим цикл по этим узлам-->
                         <xsl:for-each select="popular/item">
                              <xsl:sort select="@order" data-type="number" order="ascending"/>

                              <!--и для каждого id товара будем вызывать темплейт item, передавая в него узел соответствующего товара, выбранный с помощью ключа-->
                              <xsl:apply-templates select="key('items_id', .)">
                                   <xsl:with-param name="ordered_count" select="current()/@count"/>
                              </xsl:apply-templates>

                              <!--Если показываем товары в порядке убывания популярности,
                              то добавляем разбивку по N товаров в строке
                              ЗДЕСЬ.-->
                              <xsl:if test="$items_per_line &gt; 3 and position() mod $items_per_line = 3 and position() != last()">
                                   <div style="margin-top:20px;" class="clear"/>
                              </xsl:if>
                         </xsl:for-each>
                    </xsl:when>

                    <!--а в случае рандомного показа просто вызовем темплейт item для всех товаров описанных в XML-->
                    <xsl:otherwise>
                         <xsl:apply-templates select="shop_item"/>
                    </xsl:otherwise>
               </xsl:choose>

               <div class="clear"></div>
          </xsl:if>
     </xsl:template>

     <!-- Шаблон для товара -->
     <xsl:template match="shop_item">
          <div class="shop-item">
               <div class="inner">
                    <a href="{url}" title="Подробная информация // {name} // {shop_producer/name}"  class="item-images-inner">

                         <!-- Изображение для товара, если есть -->
                         <xsl:choose>
                              <xsl:when test="image_small!=''" >
                                   <img src="{dir}{image_small}" alt="{name}" class="item-image"  />
                              </xsl:when>
                              <xsl:otherwise>
                                   <img src="/images/no_img.jpg"  alt="{name}" />
                              </xsl:otherwise>
                         </xsl:choose>

                         <img src="/images/bg-item.png" alt="{name}" class="item-image-back"  />
                    </a>
                    <xsl:if test="property_value[tag_name = 'hit'] != ''">
                         <span class="hit"></span>
                    </xsl:if>

                    <!-- Название товара -->
                    <span class="price">
                         <xsl:value-of select="shop_producer/name" />
                         <!--<xsl:value-of disable-output-escaping="yes" select="name"/>--><xsl:text> / </xsl:text>

                         <xsl:if test="marking != ''">
                         <span><xsl:value-of disable-output-escaping="yes" select="marking"/></span><xsl:text> / </xsl:text>
                         </xsl:if>

                         <!-- Цена товара -->
                         <xsl:choose>
                              <xsl:when test="price != 0">
                                   <span>
                                        <xsl:variable name="price" select="price"/>
                                        <xsl:value-of select="format-number($price, '### ##0', 'my')"/>&#xA0;
                                        <!-- Валюта товара -->
                                        <xsl:value-of disable-output-escaping="yes" select="currency"/>
                                   </span>
                              </xsl:when>
                              <xsl:otherwise>
                                   <span class="shop_price">под заказ</span>
                              </xsl:otherwise>
                         </xsl:choose>

                         <!-- Если цена со скидкой - выводим ее -->
                         <xsl:if test="price_tax != price">
                              <span style="color: gray; text-decoration: line-through;">
                                   <xsl:variable name="price_tax" select="price_tax"/>
                                   <span style="font-size: 11pt">
                                        <xsl:value-of select="format-number($price_tax, '### ##0', 'my')"/>&#xA0;<xsl:value-of disable-output-escaping="yes" select="currency"/>
                                   </span>
                              </span>
                         </xsl:if>

                    </span>
               </div>
               <div class="clear"></div>
          </div>
          <!-- Перевод строки после каждого 3-го элемента -->
          <xsl:if test="((position() - 3) mod 3 = 0) and position() != last()">
               <xsl:text disable-output-escaping="yes">
                    &lt;/div&gt;
                    &lt;div class="wrapper"&gt;
               </xsl:text>
          </xsl:if>
     </xsl:template>

     <!-- Склонение после числительных -->
     <xsl:template name="declension">
          <xsl:param name="number" select="number"/>
          <!-- Именительный падеж -->
          <xsl:param name="nominative" select="nominative"/>
          <!-- Родительный падеж, единственное число -->
          <xsl:param name="genitive_singular" select="genitive_singular"/>
          <!-- Родительный падеж, множественное число -->
          <xsl:param name="genitive_plural" select="genitive_plural"/>

          <xsl:variable name="last_digit">
               <xsl:value-of select="$number mod 10"/>
          </xsl:variable>

          <xsl:variable name="last_two_digits">
               <xsl:value-of select="$number mod 100"/>
          </xsl:variable>
          <xsl:choose>
               <xsl:when test="$last_digit = 1 and $last_two_digits != 11">
                    <xsl:value-of select="$nominative"/>
               </xsl:when>
               <xsl:when test="$last_digit = 2 and $last_two_digits != 12 or $last_digit = 3 and $last_two_digits != 13 or $last_digit = 4 and $last_two_digits != 14">
                    <xsl:value-of select="$genitive_singular"/>
               </xsl:when>
               <xsl:otherwise>
                    <xsl:value-of select="$genitive_plural"/>
               </xsl:otherwise>
          </xsl:choose>
     </xsl:template>
</xsl:stylesheet>
XSL