Здравсвуйте. На сайте находится несколько меню.
Распределение их происходит с помощью выборки из content menu определенных пунктов меню с метками, в этом случае bottom_menu.
Мне необходимо первому тэгу li присвоить класс first.
Но он не присваевается.
Собственно код:
<xsl:apply-templates select="document('udata://content/menu/')/udata" mode="bottom_menu"/>
<xsl:template match="udata[@method = 'menu']" mode="bottom_menu">
<ul >
<xsl:apply-templates select="items/item" mode="bottom_menu" />
</ul>
</xsl:template>
<xsl:template match="item" mode="bottom_menu">
<xsl:variable name="test" select="document(concat('upage://',@id, '.bottom_menu'))/udata/property/value" />
<xsl:if test="$test !=0">
<li>
<xsl:if test="position() = 1"><!-- тут и закрывается ошибка -->
<xsl:attribute name="class">first</xsl:attribute>
</xsl:if>
<a href="{@link}" >
<xsl:value-of select="." />
</a>
</li>
</xsl:if>
</xsl:template>
Собстенно, если заменить position()=1 на 6(т.к. это 6 пункт меню в админке). То все работает. Но это временная мера.
И сам вопрос: Как это сделать более красиво, что ли. Что бы, если в будущем добавлю еще пунктов меню, не расползлось все.
class не присваивается, так как первый item, скорее всего, просто не прошел проверку
<xsl:if test="$test !=0">
, а остальные уже не первые...
Так что вижу тут 2 варианта
1. Добавляете информацию из поля bottom_menu в xml который возвращает макрос content menu и правильно формируете вызов при переборе item.
То есть вызов выглядит так:
<xsl:apply-templates select="document('udata://content/menu/?extProps=bottom_menu')/udata" mode="bottom_menu"/>
а шаблоны для вывода так:
<xsl:template match="udata[@method = 'menu']" mode="bottom_menu">
<ul >
<xsl:apply-templates select="items/item[not(//property[@name='bottom_menu']/value=0)]" mode="bottom_menu" />
</ul>
</xsl:template>
<xsl:template match="item" mode="bottom_menu">
<li>
<xsl:if test="position() = 1"><!-- тут и закрывается ошибка -->
<xsl:attribute name="class">first</xsl:attribute>
</xsl:if>
<a href="{@link}" >
<xsl:value-of select="." />
</a>
</li>
</xsl:template>
Этот вариант, к тому же, немного сократить потребность в ресурсах, при выводе меню
2. Используете usel выборку вместо content menu макроса. И там прописываете условие, что вас интересуют страницы с отмеченной галочкой bottom_menu. Пример, создание альтернативного меню, используя usel описан в этой статье http://umihelp.ru/articles/usel-multilevel-menu/
а нельзя просто 2 шаблона написать для 1го и для всех остальных?
На сколько я слышала, рекоммендуют лучше шаблонами обойтись, нежели операторами условия.
<xsl:template match="udata[@method = 'menu']" mode="bottom_menu">
<ul >
<xsl:apply-templates select="items/item[not(//property[@name='bottom_menu']/value=0)]" mode="bottom_menu" />
</ul>
</xsl:template>
<xsl:template match="item" mode="bottom_menu">
<li>
<a href="{@link}" >
<xsl:value-of select="." />
</a>
</li>
</xsl:template>
<xsl:template match="item[1]" mode="bottom_menu">
<li class="fist">
<a href="{@link}" >
<xsl:value-of select="." />
</a>
</li>
</xsl:template>
niakriss
Попробовал ваш пример. Не вышло, выводит просто основное меню и ничего больше.
И еще вопрос
<xsl:apply-templates select="items/item[not(//property[@name='bottom_menu']/value=0)]" mode="bottom_menu" />
Чем нибудь отличается от
<xsl:apply-templates select="items/item[(//property[@name='bottom_menu']/value=1)]" mode="bottom_menu" />
?
перепроверил еще раз уже на рабочем варианте. вместо вашей галочки bottom_menu использовал галочку robots_deny ("Запретить индексацию поисковиками"), то есть к двум из пунктам меню я добавил данную галочку и в итоге получал список из этих двух пунктов при том что position() возвращал в их случае 1 и 2 (то есть вопрос с выводом класса first тоже решался)
Привожу копию шаблонов
Вызов:
<xsl:apply-templates select="document('udata://content/menu/?extProps=robots_deny')" mode="new_menu" />
шаблоны меню:
<xsl:template match="udata[@method = 'menu']" mode="new_menu">
<ul umi:element-id="0" umi:module="content" umi:region="list" umi:sortable="sortable" umi:add-method="popup">
<xsl:apply-templates select="items/item[.//property[@name='robots_deny']/value=1]" mode="new_menu" />
</ul>
</xsl:template>
<xsl:template match="item" mode="new_menu">
<li>
<a href="{@link}" umi:element-id="{@id}" umi:region="row" umi:field-name="name" umi:empty="&empty-section-name;" umi:delete="delete">
~<xsl:value-of select="position()" />~
<xsl:value-of select="text()" />
</a>
</li>
</xsl:template>
P.S. едиственное что поменялось в шаблоне, это синтаксис условия выборки item items/item[.//property[@name='robots_deny']/value=1]
видимо в нем и была ошибка
Если я ничего не "навертел" в коде
<xsl:template match="udata[@method = 'menu']" mode="bottom_menu">
<ul umi:element-id="0" umi:module="content" umi:region="list" umi:sortable="sortable" umi:add-method="popup">
<xsl:apply-templates select="items/item[.//property[@name='bottom_menu']/value=1]" mode="bottom_menu" />
</ul>
</xsl:template>
<xsl:template match="item" mode="bottom_menu">
<li>
<xsl:if test="position() = 1">
<xsl:attribute name="class">first</xsl:attribute>
</xsl:if>
<a href="{@link}" >
<xsl:value-of select="." />
</a>
</li>
</xsl:template>
то у меня непобедимый сайт. Все равно не выводит.
шаблон вроде верный, а вы проверяли срабатывает ли у вас параметр ?extProps. то есть пробовали посмотреть через <xsl:copy-of select="document('udata://content/menu/?extProps=robots_deny')" mode="new_menu" /> выводит ли система доп поля?
Все выяснил, версия не дотягивает.
Из размышлений
<xsl:apply-templates select="items/item[not(//property[@name='bottom_menu']/value=0)]" mode="bottom_menu" />
У bottom_menu нет значения 0. Если он вообще присутствует то value=1, при отсутствии самого property нет.
Можно и в большинстве случаев именно так я и делаю и рекомендую делать слушателям курсов, но <xsl:if /> все равно продолжаю использовать.Например, в ситуации, когда мне надо добавить класс в верстку в зависимости от позиции элемента в xml документе (особенно если их несколько, например класс для первого, для последнего, для четного). В этом случае удобнее делать это в одном шаблоне иначе сэкономив на быстроте выполнении той или иной организации шаблона, вы можете потерять в скорости обработки из-за возрастания количества шаблонов.
Вставлю свои 5 копеек :) If использую в редких случаях, когда, например, нужно проверить, есть ли в корзине товары, но при этом не хочется городить дополнительные template.
Обычно класс для элемента вставляю с помощью конструкции (если уверен, что класс будет в любом случае)
<li>
<xsl:attribute name="class"><xsl:apply-templates select="." mode="additional-class" /></xsl:attribute>
</li>
<xsl:template macth="item[first()]" mode="additional-class">first</xsl:template>
<xsl:template macth="item[last()]" mode="additional-class">last</xsl:template>
Или, если в некоторых случаях класс не нужен, то:
<li>
<xsl:apply-templates select="." mode="additional-class" />
</li>
<xsl:template macth="item" mode="additional-class" />
<xsl:template macth="item[first()]" mode="additional-class">
<xsl:attribute name="class">first</xsl:attribute>
</xsl:template>
e.ioffe
Ничего более здравого не придумал, в прменении твоего примера. Хотя сам понимаю, что код бредовый.
Кто нибудь может подсказать, что именно не так и как сделать чтобы было так?
<xsl:template match="udata[@method = 'menu']" mode="bottom_menu">
<ul >
<xsl:apply-templates select="items/item" mode="bottom_menu" />
</ul>
</xsl:template>
<xsl:template match="item" mode="bottom_menu">
<xsl:variable name="test" select="document(concat('upage://',@id, '.bottom_menu'))/udata/property/value" />
<xsl:if test="$test !=0">
<xsl:apply-templates select="." mode="additional-class" />
</xsl:if>
</xsl:template>
<xsl:template macth="item" mode="additional-class" >
<li>
<a href="{@link}" ><xsl:value-of select="." /></a>
</li>
</xsl:template>
<xsl:template macth="item[first()]" mode="additional-class">
<li>
<xsl:attribute name="class">first</xsl:attribute>
<a href="{@link}" ><xsl:value-of select="." /></a>
</li>
</xsl:template>
может уже ну его, через макрос menu, может через usel попробовать? там при выборке сразу можно будет поставить проверку на это поле bottom_menu
P.S. Кстати, этот то вариант работает?
Не сторонник использовать usel там, где можно обойтись стандартными udata :)
Именно для этого случая я бы использовал следующий код:
<xsl:apply-templates select="document('udata://content/menu/?extProps=bottom_menu')/udata" mode="bottom_menu" />
<xsl:template match="udata[@method = 'menu']" mode="bottom_menu" />
<xsl:template match="udata[@method = 'menu'][items/item]" mode="bottom_menu">
<ul>
<xsl:apply-templates select="items/item" mode="bottom_menu" />
</u>
</xsl:template>
<xsl:template match="item" mode="bottom_menu" />
<xsl:template match="item[extended//property[@name = 'bottom_menu']/value]" mode="bottom_menu">
<li>
<xsl:apply-templates select="." mode="additional-class" />
<a href="{@link}" ><xsl:value-of select="." /></a>
</li>
</xsl:template>
<xsl:template match="item" mode="additional-class" />
<xsl:template match="item[first()]" mode="additional-class">
<xsl:attribute name="class">first</xsl:attribute>
</xsl:template>
Во-первых, при вызове content/menu указываем, что нам нужно дополнительно получить параметр bottom_menu. Затем фильтруем в зависимости от того, есть ли у элемента этот параметр или нет.
Если есть - показываем элемент и дальше определяем, какой у него должен быть класс. Если не первый, то класс не добавляем. Если первый, то добавляем.
Как-то так :)
Да, забыл дописать проверку, есть ли вообще в выборке элементы интересные нам. Вместо
<xsl:template match="udata[@method = 'menu'][items/item]" mode="bottom_menu">
нужно указать
<xsl:template match="udata[@method = 'menu'][items/item[extended//property[@name = 'bottom_menu']/value]]" mode="bottom_menu">
уже пробовали этот вариант смотрите сообщения выше, версия не позволяет.
Ага, видел.
Тогда попробуйте так:
<xsl:template match="item" mode="bottom_menu">
<xsl:apply-templates select="document(concat('upage://', @id, '.bottom_menu'))//value" mode="select_bottom_menu">
<xsl:with-param name="item" select="." />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="value" mode="select_bottom_menu">
<xsl:param name="item" />
<li>
<xsl:if test="first()"><xsl:attribute name="class">first</xsl:attribute></xsl:if>
<a href="{$item/@link}"><xsl:value-of select="$item" /></a>
</li>
</xsl:template>
Основная мысль:
если мы проверяем item используя <xsl:if test="$test !=0">, то в дальнейшем мы не можем проверить position, так как он будет равен position данного item в items без учета if-a.
Грубо говоря:
1-й элемент - не подходит
2-й элемент - не подходит
3-й элемент - подходит, однако его position для шаблона будет 3, а не 1.
Мне кажется, что если использовать <xsl:apply-templates select="document(concat('upage://', @id, '.bottom_menu'))//value" mode="select_bottom_menu">
<xsl:with-param name="item" select="." />
</xsl:apply-templates>
, то position будет рассчитываться только для тех элементов, у которых есть value (остальные отбрасываются на уровне условия).
Возможно, что это не так - под рукой нет тестовой базы, не могу проверить.