我最近问了一个关于使用XSL / t创建网站布局和子页面Here的问题。布局将装饰子页面。我想扩展这个想法,并提出类似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>
装饰器应用于子页面后,结果 包含装饰器:body 所在的子页面的主体,装饰器: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上的子模板的结果。我需要以某种方式将该转换的结果替换为主模板title / header / content部分。
知道如何做到这一点?
我在此网站上看到:http://www.devguru.com/technologies/xslt/quickref/xslt_element_calltemplate.html 您可以在xsl:variable声明中捕获xsl:call-template的结果我只是混淆了如何使用该数据除了输出它之外...
任何帮助将不胜感激
答案 0 :(得分:2)
使用此输入:
<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中声明的空元素(否则会导致<br />
的错误行为)。可以自由查看我之前发布的网站,看看我是如何处理这些网站的。