Макеты XSLT с областью динамического содержимого - PullRequest
2 голосов
/ 13 августа 2010

Я работаю над перестройкой пользовательского интерфейса нашего веб-сайта, который полностью основан на javascript / ajax (без веской причины и довольно неэффективным образом), так что бэкэнд теперь будет выполнять большую часть генерации контента.Это приложение на C # .net.

Почти все наши страницы (которых, вероятно, 40-50 страниц) имеют одинаковый базовый макет.Я новичок в XSLT, но я проделал большую работу с фреймворками MVC, такими как Spring (java, используя Sitemesh для разметки), Symfony (PHP), немного рельсов, а также несколько других.Мне нравится иметь возможность иметь один или несколько общих шаблонов, а затем иметь определенный раздел «контент», в который попадает материал, относящийся к конкретной странице.Я не могу понять, как это сделать с XSLT.В случае этого приложения у меня есть значение, доступное мне в xml, поддерживающем страницу xslt, давайте назовем его ContentXSL, значение которого является именем файла xsl, который я хочу использовать для раздела содержимого страницы.Я знаю, что это невозможно, но было бы неплохо использовать:

 <xsl:call-template name="{$ContentXSL}" />

Тогда я мог бы просто поместить это в раздел контента. Однако это невозможно, поэтому вместо этого мне понадобится массивный оператор выбора.это вызывает правильный шаблон, основанный на переменной ContentPage. Это также означает, что в моем файле Layout.xsl мне нужно будет включить все 40-50 документов xsl. Я думаю, что издержки будут довольно большими, но я не увереноб этом.Разумно ли это делать, если сайт получает много трафика?

Каковы другие распространенные способы сделать это?Похоже, что большинство современных фреймворков позволяют использовать этот шаблон для украшения контента.В случае Symfony он работал очень хорошо и был довольно гибким (со слотами и всем этим).

Я знаю, что другое потенциальное решение - это иметь 40 независимых файлов, которые имеют одинаковую разметку и включают специальные разделы, такие какВерхний и нижний колонтитулы.Это означает, что если я хочу изменить общую структуру макета моего сайта, мне придется редактировать все 40-50 страниц (очень раздражает).

Обновление - Больше объяснений

Я хочу дополнительно объяснить это, потому что у меня есть определенные требования, которые потребуют значительных технических изменений.Во-первых, бэкэнд передаст мне какой-то xml-файл, который сообщит мне об аргументах запроса в URL веб-сайта. Кроме того, он передаст мне данные, необходимые для построения моей страницы (данные вформа бизнес-данных, без HTML или что-то подобное).Данные выглядят примерно так:

<xml>
 <section>Blogs</section>
 <page>showAll</section>
  <data>
   <blogs>
     <blog>
       <author>somebody</author>
       <title></title>
       <content>..</content>
    </blog>
    </blog>..</blog>
   </blogs>    
  </data>
</xml>

Теперь нам нужно иметь шаблон страницы, подобный этому:

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt'>  
 <xsl:output omit-xml-declaration='yes' method='html' media-type='text/html' indent='yes' />
 <xsl:include href="Header.xsl"/>
 <xsl:include href="Nav.xsl"/> 
 <xsl:template name='MainLayout' match='*'>
 <html>
  <head>
   <title></title>
  </head>
  <body>
    <div id="header"><xsl:call-template name="Header" /></div>
    <div id="nav"><xsl:call-template name="Nav" /></div>
    <div id="content">
      [here is where i want to use the xsl from {/xml/section}/{/xml/page}.xsl]
    </div>
  </body>
</html>
</xsl:template>    
</xsl:stylesheet>

Теперь для содержания этой страницы у меня будет следующееfile: Blogs / showAll.xsl

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt'>  
      <xsl:output omit-xml-declaration='yes' method='html' media-type='text/html' indent='yes' />
<xsl:template name='Blogs_ShowAll'>
  <div id="blogs-showAll">
   ..iterate over /xml/data/blogs converting to html
  </div>
</xsl:template>
</xsl:stylesheet>

Решения до сих пор были хорошими, но я смог полностью переварить только одно из них (то, в котором упоминаются все файлы xsl и использование xsl: selectвыбрать правильный).Я не уверен, как применить метод FXSL к рассматриваемой проблеме.Обратите внимание, что я не буду возражать против использования подхода типа sitemesh, в котором я указываю теги html / body и все это в дочернем элементе, чтобы он заменял то, что у меня есть в разделе body дочернего элемента, на div содержимого макета (также, еслив дочернем элементе есть тег заголовка, замените тег заголовка в макете - все в таком духе).

Ответы [ 4 ]

2 голосов
/ 13 августа 2010
 <xsl:call-template name="{$ContentXSL}" />

Хотя это синтаксически недопустимо во всех версиях XSLT , с использованием шаблонов XSLT в качестве функций более высокого порядка реализовано и используется в Библиотека FXSL с тех пор, как десять лет назад .

Вот несколько упрощенное представление о том, как этого можно достичь:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:param name="pFunction1">
   <fun name="increment"/>
 </xsl:param>

 <xsl:param name="pFunction2">
   <fun name="double"/>
 </xsl:param>

 <xsl:variable name="vFunIncrement" select=
 "document('')/*/xsl:param[@name='pFunction1']/*"/>

 <xsl:variable name="vFunDouble" select=
 "document('')/*/xsl:param[@name='pFunction2']/*"/>

 <xsl:variable name="vInput" select="."/>

 <xsl:template match="/">
  increment(<xsl:value-of select="$vInput"/>) = <xsl:text/>

  <xsl:apply-templates select="$vFunIncrement">
    <xsl:with-param name="parg1" select="$vInput"/>
  </xsl:apply-templates>

  double(<xsl:value-of select="$vInput"/>) = <xsl:text/>

  <xsl:apply-templates select="$vFunDouble">
    <xsl:with-param name="parg1" select="$vInput"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="fun[@name='double']">
  <xsl:param name="parg1"/>

  <xsl:value-of select="2*$parg1"/>
 </xsl:template>

 <xsl:template match="fun[@name='increment']">
  <xsl:param name="parg1"/>

  <xsl:value-of select="$parg1+1"/>
 </xsl:template>
</xsl:stylesheet>

при применении этого преобразования кследующий XML-документ :

<num>2</num>

результат :

  increment(2) = 3

  double(2) = 4

Do note :

  1. Элементы <fun> могут быть переданы извне в преобразование через параметры глобального уровня.Это означает, что преобразование не знает, какие функции будут выполняться.

  2. Функции моделируются с помощью шаблонов соответствующих fun элементов, которые имеют определенное значение для своихname атрибут.

Если вы хотите прочитать и понять FXSL, это два лучших материала:

  1. FXSL 1.x (для XSLT 1.0)
  2. FXSL 2.0 (для XSLT 2.0)
1 голос
/ 15 августа 2010

ОП предоставил дополнительные сведения о своей проблеме, и этот ответ предоставляет дополнительное решение, которое сейчас запрашивается.

I.Идея:

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <html>
   <xsl:apply-templates select="*/page"/>
  </html>
 </xsl:template>

 <xsl:template match="page[. = 'showAll']">
   <!-- Transform all data to html -->
   <xsl:apply-templates select="../*/blogs" mode="showAll"/>
 </xsl:template>

 <xsl:template match="page[. = 'showBrief']">
   <!-- Transform the data to Summary html -->
      <xsl:apply-templates select="../*/blogs" mode="showBrief"/>
 </xsl:template>

 <xsl:template match="blogs" mode="showAll">
  <h1>All Blogs: </h1>
  <table border="1">
    <xsl:apply-templates mode="showAll"/>
  </table>
 </xsl:template>

 <xsl:template match="blog" mode="showAll">
  <tr>
    <td>Blog of <xsl:value-of select="author"/></td>
    <td><xsl:value-of select="title"/></td>
  </tr>
  <tr>
    <td colspan="2"><xsl:apply-templates select="content/node()" mode="showAll"/></td>
  </tr>
  <xsl:if test="not(position()=last())">
   <tr><td colspan="2">&#xA0;</td></tr>
  </xsl:if>
 </xsl:template>

  <xsl:template match="blogs" mode="showBrief">
  <h1>Blogs Summary: </h1>
  <table border="1">
    <xsl:apply-templates mode="showBrief"/>
  </table>
  </xsl:template>

   <xsl:template match="blog" mode="showBrief">
     <tr>
      <td>
        <xsl:value-of select="concat(author, ': ', title)"/>
      </td>
     </tr>
   </xsl:template>

</xsl:stylesheet>

при применении к этому документу XML (на основе предоставленного текста XML,но делая его правильно сформированным и более содержательным):

<xml>
 <section>Blogs</section>
 <page>showAll</page>
 <data>
   <blogs>
     <blog>
       <author>John Smith</author>
       <title>All about golden fish</title>
       <content>
       Here I publish my latest achievements
       in raising golden fish.
       </content>
    </blog>
     <blog>
       <author>Mary Jones</author>
       <title>Knitting, Knitting, Knitting</title>
       <content>
       How to knit a sharf.
       </content>
    </blog>
   </blogs>
 </data>
</xml>

производит желаемый тип вывода "show-all" :

<html>
   <h1>All Blogs: </h1>
   <table border="1">
      <tr>
         <td>Blog of John Smith</td>
         <td>All about golden fish</td>
      </tr>
      <tr>
         <td colspan="2">
            Here I publish my latest achievements
                   in raising golden fish.

         </td>
      </tr>
      <tr>
         <td colspan="2">&nbsp;</td>
      </tr>
      <tr>
         <td>Blog of Mary Jones</td>
         <td>Knitting, Knitting, Knitting</td>
      </tr>
      <tr>
         <td colspan="2">
                   How to knit a sharf.

         </td>
      </tr>
   </table>
</html>

Теперь мы изменим документ XML и заменим элемент page на этот :

 <page>showBrief</page>

Когда то же преобразование применяется к обновленному документу XML,теперь он производит желаемый итоговый вывод :

<html>
   <h1>Blogs Summary: </h1>
   <table border="1">
      <tr>
         <td>John Smith: All about golden fish</td>
      </tr>
      <tr>
         <td>Mary Jones: Knitting, Knitting, Knitting</td>
      </tr>
   </table>
</html>

II.Следующий шаг

На практике все шаблоны в данном режиме будут находиться в отдельном файле xsl и будут импортированы основной таблицей стилей:

Преобразование (основная таблица стилей), таким образом, становится :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:import href="showAll.xsl"/>
 <xsl:import href="showBrief.xsl"/>

 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <html>
   <xsl:apply-templates select="*/page"/>
  </html>
 </xsl:template>
</xsl:stylesheet>

Примечание :

  1. Преобразование заранее не знает, какие шаблоны будутapply - преобразование полностью управляется данными.

  2. Шаблоны, которые не существуют сейчас, могут быть написаны в будущем и будут применяться безнеобходимо изменить основную таблицу стилей.

  3. Нет условной логики , <xsl:choose> инструкции и т. д. Это истинная сила шаблонов xsl в действии.

  4. Это преобразование основано на той же идее, на которой основан FXSL .

0 голосов
/ 13 августа 2010

Помимо превосходного ответа Димитре, рекомендующего метод для реализации функций более высокого порядка, вы также можете использовать метод с мастер-страницами и дочерними страницами в сочетании с неким кодом, например:

MasterContent.xml:

<title>Test for XSLT</title>

MasterLayout.xml:

<html>
    <head>
        <title></title>
    </head>
    <body>
        <p>This is master page</p>
    </body>
</html>

Master.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pMasterLayout" select="document('MasterLayout.xml')"/>
    <xsl:param name="pMasterContent" select="document('MasterContent.xml')"/>
    <xsl:output method="xml"/>
    <xsl:template match="/">
        <xsl:apply-templates select="$pMasterLayout/*"/>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="title">
        <xsl:copy>
            <xsl:value-of select="$pMasterContent/title"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

ChildLayout:

<html>
    <head>
        <title></title>
    </head>
    <body>
        <h1></h1>
    </body>
</html>

Итак, это преобразование("Child.xsl"):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:include href="Master.xsl"/>
    <xsl:param name="pChildLayout" select="document('ChildLayout.xml')"/>
    <xsl:param name="pChildContent" select="/"/>
    <xsl:template match="body">
        <xsl:copy>
            <xsl:apply-templates select="$pChildLayout/html/body/*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="h1">
        <xsl:copy>
            <xsl:value-of select="$pChildContent/header"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

С этим входом ("ChildContent"):

<header>Child Content</header>

Выход:

<html>
    <head>
        <title>Test for XSLT</title>
    </head>
    <body>
        <h1>Child Content</h1>
    </body>
</html>

Примечание:

Проверьте лучший пример на aranedabienesraices.com.ar Я рекомендую использовать @id в качестве якорей для наполнения макета содержимым (вы можете удалить их с пустыми шаблонами).Этот метод не привязывает вас к какой-либо IDE поставщика (с понятием XSLT) для создания страниц макета.

0 голосов
/ 13 августа 2010

Пример Димитра хорош ..

Вот способ сделать это также .. немного уродливое решение, но делает трюк

primary.xsl

<xsl:variable name="ContentXSL" select="/your/xml/settings/@content" />

<!-- Reference templates -->
<xsl:include href="template1.xsl" />
<xsl:include href="template2.xsl" />
<xsl:include href="template3.xsl" />
<xsl:include href="template4.xsl" />

<xsl:template match="/">
  <html>
    <head>
      <title>..</title>
    </head>
  </html>
  <body>
    <xsl:call-template name="getcontent" />
  </body>
</xsl:template>

<xsl:template name="getcontent">
  <xsl:choose>
    <xsl:when test="$ContentXSL = 'template1'">
      <xsl:apply-templates match="/your/xml/structure" mode="template1" />
    </xsl:when>
    <xsl:when test="$ContentXSL = 'template2'">
      <xsl:apply-templates match="/your/xml/structure" mode="template2" />
    </xsl:when>
    <xsl:when test="$ContentXSL = 'template3'">
      <xsl:apply-templates match="/your/xml/structure" mode="template3" />
    </xsl:when>
    <xsl:when test="$ContentXSL = 'template4'">
      <xsl:apply-templates match="/your/xml/structure" mode="template4" />
    </xsl:when>
    <xsl:otherwise>
      <!-- Default template? -->
      <xsl:apply-templates match="/your/xml/structure" mode="template1" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

template1.xsl

<xsl:template match="/your/xml/structure" mode="template1">
  Template 1<br />
</xsl:template>

template2.xsl

<xsl:template match="/your/xml/structure" mode="template2">
  Template 2<br />
</xsl:template>

template3.xsl

<xsl:template match="/your/xml/structure" mode="template3">
  Template 3<br />
</xsl:template>

template4.xsl

<xsl:template match="/your/xml/structure" mode="template4">
  Template 4<br />
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...