与 XSLT 类似的 Sitemesh 功能? [英] Sitemesh like functionality with XSLT?

查看:25
本文介绍了与 XSLT 类似的 Sitemesh 功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近问了一个关于使用 XSL/t 创建站点布局和子页面的问题 此处...布局将装饰子页面的位置.我想扩展这个想法并提出类似 SiteMesh 的功能.请注意,我将拥有很少数量的 xsl 布局文件,我的大部分 xsl 文件应该用于子页面.布局相当基本,它包括一个页眉、一个主菜单、一个页脚、一个正文在它下面有一个内容 div.SiteMesh 允许您将模板文件定义为一个相当标准的 html 文件,然后将覆盖父部分的子页面.例如,这是一个用于站点网格的基本模板(装饰器):

<%@ taglib prefix="decorator";uri=http://www.opensymphony.com/sitemesh/decorator";%><头><标题><decorator:title default="SiteMesh 教程示例";/>- 网站标题<style type="text/css">@import "css/global.css";</style><装饰者:头/><身体><div id="header"><h2><a href=http://www.my-site.com/">Mysite.com</a>去这里

<div id="内容"><装饰器:主体/>

然后这里将是一个子页面的示例:

<头><title>子页面</title><style type='text/css'>p {边距:10}</风格><身体>内容在这里

一旦装饰器应用于子页面,结果包含 decorator:body 所在的子页面的正文,并且 decorator:head 也被替换,等等.它的工作原理非常简单,组织网站的方式也相当有效.

所以现在假设我们正在使用 XSL/T,并且我们希望使用类似的结构,在这种结构中我们不会不断重新定义布局的外观,而是希望只定义一次(或者对于页面可能定义几次不是很相似),如果子模板有它们,我们将替换它们.听起来这很简单,但问题是支持这个网站的数据看起来像(不是真正的博客网站,只是我正在处理的一个例子)

<section>博客</section><page>用户博客</page><数据><博客><博客><title>第一个博客</title><author>John Doe</author><描述>...</描述></博客></博客></数据></xml>

那么现在假设我有一个这样的主模板:

<头><title><!-- 将其替换为子标题-->- 网站标题</title><script src="common-scripts.js"></script><style type="text/css">@import "common.css";</风格><!-- 将所有内容插入子 <head>这里除了标题--><身体><div id="header">标题/记录这里的东西</div><div id="菜单"><ul><li><a href=#">Cat 1</a></li><li><a href=#">Cat 2</a></li></ul>

<div id="内容"><!-- 用 <body>...</body> 之间的所有内容替换它在孩子 -->

<div id="footer">我的网站,版权,bla bla</div>

那么我想要做的是从上面获取那个 xml(关于博客的那个)并将它应用到我的子页面,然后获取转换的结果并将它应用到我的主模板(它将复制/应用需要的元素).我不确定是否有办法在单个转换中做到这一点.目前的架构是这样的,我提供了如图所示的 xml,我必须将它构建到一个页面中.我想也许我可以让主模板包含子模板,然后使用 xsl:call-template 包裹一个 xsl:variable 声明,用于捕获当前 xml 上子模板的结果.我需要以某种方式获取该转换的结果以替换主模板的标题/标题/内容部分.

知道如何做到这一点吗?

我在这个网站上看到:http://www.devguru.com/technologies/xslt/quickref/xslt_element_calltemplate.html您可以在 xsl:variable 声明中捕获 xsl:call-template 的结果

任何帮助将不胜感激

解决方案

有了这个输入:

<section>博客</section><page>用户博客</page><数据><博客><博客><title>第一个博客</title><author>John Doe</author><描述>...</描述></博客></博客></数据></xml>

这个master.xml"文件:

<头><title><!-- 将其替换为子标题-->- 我的网站</title><script src="common-scripts.js"></script><style type="text/css">@import "common.css" </style><!-- 将所有内容插入子 <head>这里除了标题--><身体><div id="header">标题/记录这里的东西</div><div id="菜单"><ul><li><a href="#">Cat 1</a><li><a href="#">Cat 2</a>

<div id="内容"><!-- 用两者之间的所有内容替换它<body>...</body>在孩子 -->

<div id="footer">我的网站,版权,bla bla</div>

这个child.xml"文件:

<头><title>子页面</title><style type='text/css'>p { margin: 10 }</style><身体><h3 id="title">#</h3><dl><dt id="作者">#</dt><dd id="描述">#</dd></dl>

这个样式表:

<xsl:output method="xml"/><xsl:variable name="child" select="document('child.xml')"/><!-- 从这里到下一条评论可以在其他样式表中像 "master.xsl" 并包含在 "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:模板><xsl:template match="/"><xsl:apply-templates select="$master/*"><xsl:with-param name="context" select="/"/></xsl:apply-templates></xsl:模板><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:模板><xsl:template match="title/comment()"><xsl:param name="context"/><xsl:value-of select="$context/xml/page"/></xsl:模板><xsl:template match="head/comment()"><xsl:param name="context"/><xsl:应用模板select="$child/html/head/node()[not(self::title)]"><xsl:with-param name="context" select="$context"/></xsl:apply-templates></xsl:模板><!-- 要包含的可能的master.xsl"到此结束--><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:模板><xsl:template match="*[@id='author']/text()"><xsl:param name="context"/><xsl:value-of select="$context/author"/></xsl:模板><xsl:template match="*[@id='description']/text()"><xsl:param name="context"/><xsl:value-of select="$context/description"/></xsl:模板></xsl:stylesheet>

输出:

<头><title>用户博客 - 我的网站</title><script src="common-scripts.js"></script><style type="text/css">@import "common.css" </style><style type="text/css">p { margin: 10 }</style><身体><div id="header">标题/记录这里的东西</div><div id="菜单"><ul><li><a href="#">Cat 1</a><li><a href="#">Cat 2</a>

<div id="内容"><h3 id="title">第一个博客</h3><dl><dt id="author">John Doe</dt><dd id="描述">...</dd></dl>

<div id="footer">我的网站,版权,bla bla</div>

注意:这只是一个例子.有待改善.人口模式的主要问题:逻辑是遍历布局,而不是数据,主要是身份转换;你需要在布局中有一些锚点来引用数据(这是一个很大的改进,例如,通过自己的命名空间,通过像 id="include:some-data" 等特定模式.);如果它们是 @id,则需要删除这些锚点;对于文本替换在布局中使用虚拟文本节点,这仅使用 xsl:value-of 简化了内容模板;穷人的隧道模式"(Dimitre 调用)用于传递数据上下文,主要是因为迭代人口.其他问题:在处理 XHTML(比 HTML 更好)时要注意:DOCTYPE 主要用于 IE7(松散改进的 CSS 处理,否则),在 DTD 中声明的空元素(<br/> 否则).可以随意查看我之前发布的网站,看看我是如何处理这些问题的.

I recently asked a question about using XSL/t for creating a site layout and child pages Here.. Where the layout would decorate the child page. I want to expand on that idea and come up with SiteMesh like functionality. Note that I'm going to have a very small number of xsl layout files, most of my xsl files should be for the child pages.. The layout is fairly basic, it includes a header, a main menu, a footer, a body with a content div under it. SiteMesh allows you to define template files as a fairly standard html file, and then child pages which will override sections of the parent. For instance, here is a basic template (decorator) for 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>

And then here would be an example of a child page:

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

Once the decorator is applied to the child page, the result contains the body of the child page where the decorator:body was at, and the decorator:head gets replaced as well, etc.. Pretty simple how it works and fairly effective way of organizing a site.

So now lets say we are using XSL/T instead and we want to use a similar structure where we don't keep redefining what the layout looks like, rather we define that hopefully only once (or maybe a few times for pages that aren't very similar), and we replace out sections if the child template has them. Sounds like this would be very simple, but the problem is that the data backing this site will look like (not really a blog site but just as an example of what i'm dealing with)

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

So now Lets say I have a master template like this:

<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>

So then what I want to do is take that xml from above (the one about blogs) and apply that to my child page, and take the result of that transformation and apply it to my master template (which will copy/apply elements as needed). I'm not sure if there is a way to do this in a single transformation. Currently the architecture is such that I'm provided with the xml as shown, and I have to construct that into a page.. I thought maybe I could have the master template include the child template, then use xsl:call-template wrapped in an xsl:variable declaration to capture the results of the child template on the current xml.. I need to somehow take the results of that transformation to replace the master templates title/header/content section.

Any idea how this can be done?

I see on this site: http://www.devguru.com/technologies/xslt/quickref/xslt_element_calltemplate.html that you can capture the results of a xsl:call-template in the xsl:variable declaration I'm just confused how you can then use that data besides ouputing it..

Any help would be appreciated

解决方案

With this input:

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

This "master.xml" document:

<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>

This "child.xml" document:

<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>

This stylesheet:

<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>

Output:

<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>

Note: This is just an example. Could be better. The pricipal issues about population pattern: the logic is trasverse the layout, not the data, mostly with identity transform; you need to have some anchors into the layout to reference the data (this is wide open to improve, as example, by own namespace, by specific pattern like id="include:some-data", etc.); you need to remove those anchor if they are @id; for text replacement use dummy text nodes in layout, this simplifies the content template with just xsl:value-of; "poor man's tunnel pattern" (Dimitre calls) for passing data context, mostly because iterated population. Other issues: when dealing with XHTML (better than HTML) take care of: DOCTYPE mostly for IE7 (loose improved CSS handling, otherwise), empty elements declared in DTD (wrong behavior with <br /> otherwise). Be free to check the site I've posted earlier to see how I'd handled those.

这篇关于与 XSLT 类似的 Sitemesh 功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆