Понадобилось мне в разделе Статьи одного из проектов, что использует в качестве базиса Mozart (mozartframework.ru), реализовать в конце каждой статьи ссылку на следующую и предыдущую. Нет ничего проще, дальше по большей части будет инструкция по использованию XSLT.
Для начала я залез в XML и поправил немножко тот участок, который отвечает за вывод списка уроков и параллельно за полный вывод информации об одном уроке.
Get'ом выбираем уроки в кол-ве не более 20 и дополнительно выбираем через Info полный текст. Больше 20 нам пока не понадобится. Я лишь для наглядности привел такую реализацию выборки данных для списка и полного вывода через newt:include, чтобы было более понятно (на самом деле способов сделать это множество). По тексту ясно, что один участок для списка, а второй — для полного текста. В реальной системе все несколько лаконичней описано.
Теперь самая главная фишка — это разворачиваемость объектов. Она нам тут поможет тем, что не заставит нас совершать какие-то сложные действия для того, чтобы выбрать предыдущий и следующий уроки. Когда мы используем get и не указываем дополнительных ограничений по id (именно id), то мы можем использовать понятие разворачиваемости вот каким образом. Если в query (в данном случае в виде параметра через УРЛ) мы подаем параметр lesson_id, и этот параметр пропускаем до нашего newt:base и инструкции get, инструкция эта ведет себя особенным образом: разворачивается (т.е. выбираются полные даные по объекту и все его вложенные инструкции типа info и т.п.) только тот объект, чей id совпадает с переданными нами. Остальные объекты будут просто идти в виде краткой записи в XML до и после развернутого.
Т.е. на выходе в случае наличия lesson_id=85 мы получим:
Далее нам осталось только правильно обработать данный XML в XSLT трансформе, а это просто. Под текстом урока ставим вызов нужного созданного нами позже темплейта:
В самом темплейте мы используем оси (preceding-sibling и following-sibling) а так же через указания номера элемента ([1]) указываем, какой именно нам нужен, ведь мы хотим поставил ссылку только на один элемент вперед и один элемент назад. Это чистый XSLT и никаких приблуд от Mozart тут нет.
Для начала я залез в XML и поправил немножко тот участок, который отвечает за вывод списка уроков и параллельно за полный вывод информации об одном уроке.
Copy Source | Copy HTML<br/><!-- Если lesson_id НЕ подается в УРЛ --><br/> <br/><newt:include match="query[lesson_id/@value='' or not(lesson_id)]"><br/> <newt:base id="lessons-list" add-query="lessons-list" query-filter="lesson_id"><br/> <request><br/> <get limit="20" object="lesson" sort="sort"><br/> <info attr="shortdescription"/><br/> </get><br/> </request><br/> </newt:base><br/></newt:include><br/> <br/><!-- Если lesson_id подается в УРЛ --><br/> <br/><newt:include match="query[lesson_id/@value!='']"><br/> <newt:base id="lessons-list" add-query="lessons-list" query-filter="lesson_id"><br/> <request><br/> <get limit="20" object="lesson" sort="sort"><br/> <info attr="description"/><br/> </get><br/> </request><br/> </newt:base><br/></newt:include> <br/>
Get'ом выбираем уроки в кол-ве не более 20 и дополнительно выбираем через Info полный текст. Больше 20 нам пока не понадобится. Я лишь для наглядности привел такую реализацию выборки данных для списка и полного вывода через newt:include, чтобы было более понятно (на самом деле способов сделать это множество). По тексту ясно, что один участок для списка, а второй — для полного текста. В реальной системе все несколько лаконичней описано.
Теперь самая главная фишка — это разворачиваемость объектов. Она нам тут поможет тем, что не заставит нас совершать какие-то сложные действия для того, чтобы выбрать предыдущий и следующий уроки. Когда мы используем get и не указываем дополнительных ограничений по id (именно id), то мы можем использовать понятие разворачиваемости вот каким образом. Если в query (в данном случае в виде параметра через УРЛ) мы подаем параметр lesson_id, и этот параметр пропускаем до нашего newt:base и инструкции get, инструкция эта ведет себя особенным образом: разворачивается (т.е. выбираются полные даные по объекту и все его вложенные инструкции типа info и т.п.) только тот объект, чей id совпадает с переданными нами. Остальные объекты будут просто идти в виде краткой записи в XML до и после развернутого.
Т.е. на выходе в случае наличия lesson_id=85 мы получим:
Copy Source | Copy HTML<br/><base id="lessons-list" add-query="lessons-list" ... ><br/> <lesson id="83" query="&lesson_id=83" title="Урок 1: Создание новой страницы"/><br/> <lesson id="84" query="&lesson_id=84" title="Урок 2: Навигация по сайту"/><br/> <lesson id="85" query="&lesson_id=85" title="Урок 3: Работа с БД"><br/> <description><br/> ...<br/> </description><br/> </lesson><br/> <lesson id="86" query="&lesson_id=86" title="Урок 4: Создание раздела Новости"/><br/> <lesson id="87" query="&lesson_id=87" title="Урок 5: Репликация"/><br/> <lesson id="88" query="&lesson_id=88" title="Урок 6: Работа с формами"/><br/></base> <br/>
Далее нам осталось только правильно обработать данный XML в XSLT трансформе, а это просто. Под текстом урока ставим вызов нужного созданного нами позже темплейта:
Copy Source | Copy HTML<br/><xsl:template match="lesson[description]"><br/> ...<br/> ...<br/> <xsl:apply-templates select="." mode="pagelisting"/><br/></xsl:template><br/> <br/><xsl:template match="lesson[description]" mode="pagelisting"><br/> <p style="text-align: center;"><br/> <xsl:if test="preceding-sibling::lesson[1]"><br/> <a href="/docs.xml?lesson_id={preceding-sibling::lesson[1]/@id}"><xsl:value-of select="preceding-sibling::lesson[1]/@title"/></a><br/> </xsl:if><br/> <xsl:if test="preceding-sibling::lesson[1] and following-sibling::lesson[1]"> | </xsl:if><br/> <xsl:if test="following-sibling::lesson[1]"><br/> <a href="/docs.xml?lesson_id={following-sibling::lesson[1]/@id}"><xsl:value-of select="following-sibling::lesson[1]/@title"/></a> <br/> </xsl:if><br/> </p><br/></xsl:template> <br/>
В самом темплейте мы используем оси (preceding-sibling и following-sibling) а так же через указания номера элемента ([1]) указываем, какой именно нам нужен, ведь мы хотим поставил ссылку только на один элемент вперед и один элемент назад. Это чистый XSLT и никаких приблуд от Mozart тут нет.