我正在努力重建我们网站的UI部分,这些部分都是基于javascript / ajax的(基于没有充分理由和效率相当低的方式),这样后端现在将完成大部分内容生成。它是一个C#.net应用程序。
几乎所有页面(可能有40-50页)都具有相同的基本布局。我是XSLT的新手,但我已经完成了许多MVC框架的工作,例如Spring(java,使用Sitemesh进行布局),Symfony(PHP),一些rails以及其他一些。我喜欢有能力拥有一个或几个通用模板,然后有一个特定的“内容”部分,其中页面特定的东西。我无法弄清楚如何使用XSLT完成此操作。在这个应用程序的情况下,我有一个值在xml支持xslt页面的我可用,让我们称之为ContentXSL,谁的值是xsl文件的名称 我想用于页面的内容部分。我知道这不可能,但使用它会很好:
<xsl:call-template name="{$ContentXSL}" />
然后我可以简单地把它放在内容部分..然而这是不可能的,所以我需要一个基于ContentPage变量调用正确模板的大量选择语句。这也意味着在我的布局中。 xsl文件我必须包含所有40-50 xsl文件..我认为开销会很大,但我不确定。如果网站获得大量流量,这是否合理?
其他常见的做法是什么?似乎大多数现代框架允许您使用此模式来装饰内容。在Symfony的情况下,它工作得很好,非常灵活(有插槽和所有这些)。
我知道另一个可能的解决方案是拥有40个独立文件,这些文件都具有相似的标记,并包含特殊部分,如页眉和页脚。这意味着如果我想改变我网站布局的整体结构,我必须编辑所有40-50页(非常烦人)。
更新 - 更多解释
我想进一步解释这一点,因为我有一些需要大量工程改变的要求。 首先,后端将向我传递一些xml,这将让我知道查询args在网站的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>
现在,对于此页面的内容,我将拥有以下文件: 博客/ 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:选择正确的文件)。 我不确定如何将FXSL方法应用于手头的问题。 请注意,我不会反对使用sitemesh类型的方法,我指定html / body标签以及子项中的所有内容,并将它在子项的body部分中替换为布局的内容div(同样,如果在孩子中有一个标题标签替换布局中的标题标签 - 这样的东西。)
答案 0 :(得分:2)
<xsl:call-template name="{$ContentXSL}" />
虽然这在所有版本的XSLT 中在语法上都是非法的,但是使用XSLT模板,因为高阶函数已经在十年前的FXSL library中实现和使用了强>
这是一个如何实现这一点的简化概念:
<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
请注意:
答案 1 :(得分:1)
OP提供了有关其问题的更多详细信息,此答案提供了现在要求的其他解决方案。
<强>予。想法:
此转化:
<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"> </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"> </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>
请注意:
转型事先并不知道将应用哪些模板 - 转换完全由数据驱动。
现在不存在的模板可以在将来编写并将被应用,而无需更改主样式表。
没有条件逻辑,<xsl:choose>
指令等。这是xsl模板在行动中的真正力量。
此转换基于FXSL基于的相同构思。
答案 2 :(得分:0)
Dimitre的例子很好......
这是一种方法来做到这一点..一个有点丑陋的解决方案,但做的伎俩
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>
答案 3 :(得分:0)
除了优秀的Dimitre建议实现高阶函数的方法的答案之外,你还可以使用一个主页和子页面结合某种代码的方法,如下所示:
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的概念)来构建布局页面。