Ситема как функциональность с XSLT?

Недавно я задал вопрос об использовании XSL/t для создания макета сайта и дочерних страниц здесь. Где макет будет украшать дочернюю страницу. Я хочу расширить эту идею и придумать функциональность, подобную SiteMesh. Обратите внимание, что у меня будет очень небольшое количество файлов макета xsl, большинство моих файлов xsl должны быть для дочерних страниц. Макет довольно прост, он включает в себя заголовок, главное меню, нижний колонтитул, тело с содержимым div под ним. SiteMesh позволяет вам определять файлы шаблонов как довольно стандартный HTML-файл, а затем дочерние страницы, которые будут переопределять разделы родительского элемента. Например, вот базовый шаблон (декоратор) для sitemesh:

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>

<head>
  <title>
    <decorator:title default="SiteMesh Tutorial Example" /> - Site Title
  </title>
  <style type="text/css">@import "css/global.css";</style>
  <decorator:head />
  <body>
    <div id="header">
      <h2><a href="http://www.my-site.com/">Mysite.com</a> goes here</h2>
    </div>
    <div id="content">
      <decorator:body />
    </div>
  </body>
</html>

И тогда вот пример дочерней страницы:

<html>
  <head>
    <title>Child Page</title>
    <style type='text/css'> 
     p { margin: 10 }    
    </style>
  </head>
  <body>
    Content Goes here
  </body>
</html>

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

Итак, теперь давайте предположим, что мы вместо этого используем XSL/T, и мы хотим использовать аналогичную структуру, в которой мы не переопределяем то, как выглядит макет, скорее мы определяем это, надеюсь, только один раз (или, возможно, несколько раз для страниц, которые не ' очень похоже), и мы заменяем разделы, если они есть у дочернего шаблона. Похоже, это будет очень просто, но проблема в том, что данные, которые поддерживают этот сайт, будут выглядеть (на самом деле не сайт блога, а просто пример того, с чем я имею дело)

<xml>
<section>Blogs</section>
<page>UserBlogs</page>
<data>
 <blogs>
   <blog>
     <title>First Blog</title>
     <author>John Doe</author>
     <description>...</description>
   </blog>
 </blogs>
</data>
</xml>

Итак, давайте скажем, что у меня есть мастер-шаблон, подобный этому:

<html>
<head>
  <title><!-- replace this with child title --> - Site Title</title>
  <script src="common-scripts.js"></script>
  <style type="text/css">@import "common.css" </style>
  <!-- insert everything in the child <head> here except the title -->

</head>
<body>
  <div id="header">Header/log that stuff here</div>
  <div id="menu">
     <ul><li><a href="#">Cat 1</a></li><li><a href="#">Cat 2</a></li></ul>
  </div>
  <div id="content">
    <!-- replace this with everything between <body>...</body> in the child -->
  </div>
  <div id="footer">My Site, copyright, bla bla</div>
</body>
</html>

Итак, то, что я хочу сделать, это взять этот XML сверху (тот, что касается блогов) и применить его к моей дочерней странице, взять результат этого преобразования и применить его к моему основному шаблону (который будет копировать / применять элементы по мере необходимости). Я не уверен, есть ли способ сделать это в одной трансформации. В настоящее время архитектура такова, что мне предоставляется xml, как показано, и я должен построить это на странице. Я подумал, что, возможно, я мог бы сделать так, чтобы основной шаблон включал дочерний шаблон, а затем использовал xsl:call-template, обернутый в объявление xsl:variable для захвата результатов дочернего шаблона в текущем xml. Мне нужно каким-то образом использовать результаты этого преобразования для замены раздела title/header/content основных шаблонов.

Есть идеи, как это можно сделать?

Я вижу на этом сайте: http://www.devguru.com/technologies/xslt/quickref/xslt_element_calltemplate.html что вы можете захватить результаты xsl:call-шаблона в объявлении xsl:variable, я просто запутался, как затем вы можете использовать эти данные, кроме вывода их

Любая помощь будет оценена

1 ответ

Решение

С этим входом:

<xml>
    <section>Blogs</section>
    <page>UserBlogs</page>
    <data>
        <blogs>
            <blog>
                <title>First Blog</title>
                <author>John Doe</author>
                <description>...</description>
            </blog>
        </blogs>
    </data>
</xml>

Этот "master.xml" документ:

<html>
    <head>
        <title><!-- replace this with child title --> - My Site</title>
        <script src="common-scripts.js"></script>
        <style type="text/css">@import "common.css" </style>
        <!-- insert everything in the child <head> here except the title -->
    </head>
    <body>
        <div id="header">Header/log that stuff here</div>
        <div id="menu">
            <ul>
                <li>
                    <a href="#">Cat 1</a>
                </li>
                <li>
                    <a href="#">Cat 2</a>
                </li>
            </ul>
        </div>
        <div id="content">
            <!-- replace this with everything between 
                                   <body>...</body> in the child -->
        </div>
        <div id="footer">My Site, copyright, bla bla</div>
    </body>
</html>

Этот документ "child.xml":

<html>
    <head>
        <title>Child Page</title>
        <style type='text/css'>p { margin: 10 }</style>
    </head>
    <body>
        <h3 id="title">#</h3>
        <dl>
            <dt id="author">#</dt>
            <dd id="description">#</dd>
        </dl>
    </body>
</html>

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:variable name="child" select="document('child.xml')"/>

    <!-- From here to next comment could be in other stylesheet
         like "master.xsl" and included with "xsl:include"      -->

    <xsl:variable name="master" select="document('master.xml')"/>
    <xsl:template match="@*|node()">
        <xsl:param name="context"/>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:with-param name="context" select="$context"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/">
        <xsl:apply-templates select="$master/*">
            <xsl:with-param name="context" select="/"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="div[@id='content']">
        <xsl:param name="context"/>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each select="$context/xml/data/blogs/blog">
                <xsl:apply-templates select="$child/html/body/node()">
                    <xsl:with-param name="context" select="."/>
                </xsl:apply-templates>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="title/comment()">
        <xsl:param name="context"/>
        <xsl:value-of select="$context/xml/page"/>
    </xsl:template>
    <xsl:template match="head/comment()">
        <xsl:param name="context"/>
            <xsl:apply-templates 
                            select="$child/html/head/node()[not(self::title)]">
                <xsl:with-param name="context" select="$context"/>
            </xsl:apply-templates>
    </xsl:template>

    <!-- Here ends the posible "master.xsl" to be included -->

    <xsl:template match="@id[.='title']|@id[.='author']|@id[.='description']"/>
    <xsl:template match="*[@id='title']/text()">
        <xsl:param name="context"/>
        <xsl:value-of select="$context/title"/>
    </xsl:template>
    <xsl:template match="*[@id='author']/text()">
        <xsl:param name="context"/>
        <xsl:value-of select="$context/author"/>
    </xsl:template>
    <xsl:template match="*[@id='description']/text()">
        <xsl:param name="context"/>
        <xsl:value-of select="$context/description"/>
    </xsl:template>
</xsl:stylesheet>

Выход:

<html>
    <head>
        <title>UserBlogs - My Site</title>
        <script src="common-scripts.js"></script>
        <style type="text/css">@import "common.css" </style>
        <style type="text/css">p { margin: 10 }</style>
    </head>
    <body>
        <div id="header">Header/log that stuff here</div>
        <div id="menu">
            <ul>
                <li>
                    <a href="#">Cat 1</a>
                </li>
                <li>
                    <a href="#">Cat 2</a>
                </li>
            </ul>
        </div>
        <div id="content">
            <h3 id="title">First Blog</h3>
            <dl>
                <dt id="author">John Doe</dt>
                <dd id="description">...</dd>
            </dl>
        </div>
        <div id="footer">My Site, copyright, bla bla</div>
    </body>
</html>

Примечание: это всего лишь пример. Могло быть лучше. Основные вопросы о структуре населения: логика пересекает структуру, а не данные, в основном с преобразованием идентичности; вам нужно иметь несколько якорей в макете для ссылки на данные (это широко открыто, чтобы улучшить, например, собственным пространством имен, конкретным шаблоном, таким как id="include:some-data", так далее.); вам нужно удалить эти якоря, если они @id; для замены текста используйте пустые текстовые узлы в макете, это упрощает шаблон содержимого с помощью xsl:value-of; "туннельный паттерн бедняка" (вызов Димитра) для передачи контекста данных, в основном из-за повторного заполнения. Другие проблемы: при работе с XHTML (лучше, чем HTML) следует позаботиться о: DOCTYPE в основном для IE7 (плохая улучшенная обработка CSS, в противном случае), пустые элементы объявлены в DTD (неправильное поведение с <br /> иначе). Не стесняйтесь проверять сайт, который я разместил ранее, чтобы увидеть, как я справился с этим.

Другие вопросы по тегам