【问题标题】:Sitemesh like functionality with XSLT?与 XSLT 类似的 Sitemesh 功能?
【发布时间】:2011-04-01 14:04:13
【问题描述】:

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

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

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

所以现在假设我们使用的是 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 上子模板的结果。我需要以某种方式获取该转换的结果来替换主模板的标题/标题/内容部分。

知道如何做到这一点吗?

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

任何帮助将不胜感激

【问题讨论】:

  • @Matt Wolfe:这很容易完成。唯一的问题是您还没有定义如何一起处理“子模板”和您的 XML 文件以生成“最终阶段子模板”。定义这个,我会提供一个完整而详细的解决方案。
  • @Alejandro - 你的网站不是我的语言,谷歌翻译不能用它。我没有看到任何教程或示例。我第一次确实检查了它,然后我再次检查了它,它看起来像是用于房地产或其他什么的。
  • @Dimitre,正如我所展示的,我网站的后端会生成一些 xml。该框架允许您指定用于处理 xml 的 xsl 文档。现在我正在使用一个包罗万象的样式表,这样无论用户转到哪个页面,它都使用 Main.xsl 这是布局。然后布局查看 /xml/section 和 /xml/page 以确定要使用的子模板。我正在考虑通过修改后端代码以首先应用子样式表来进行两部分转换,然后将布局样式表应用于该样式表。如果可能的话,我宁愿不这样做。
  • @Matt Wolfe:Stack Overflow 不是我的语言,但我仍然可以阅读代码示例并设法理解它。但我也发布了一个答案。你对此有什么疑问吗?有什么新要求?
  • @Alajandro,感谢您的帮助,您的帖子看起来正是我所需要的。我仍在努力解决这些 xsl 的问题。您网站的问题不仅在于语言,而且即使在点击了很多页面后,我也看不到任何 xsl 示例。也许我错过了一些东西。

标签: xml xslt sitemesh


【解决方案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; “穷人的隧道模式”(Dimitre 呼吁)用于传递数据上下文,主要是因为迭代人口。其他问题:在处理 XHTML(优于 HTML)时,请注意:DOCTYPE 主要用于 IE7(否则会松散改进 CSS 处理),在 DTD 中声明的空元素(否则会出现 &lt;br /&gt; 的错误行为)。请随意查看我之前发布的网站,看看我是如何处理这些问题的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-05
    相关资源
    最近更新 更多