Dynamically decide which XSL stylesheet to use
I'm trying to create a site which (among other things) will display data which is contained in xml files. I'm using xsl stylesheets to format everything, but some of the pages have similar content. Rather than have to make multiple xml sheets with duplicate data, is there a way to tell the xsl where the data is being displayed and have it determine which layout to use.
Example:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform开发者_运维百科">
<xsl:template match="/">
<xsl:choose>
<xsl:if test="something">
<!-- Format data one way -->
</xsl:if>
<xsl:otherwise>
<!-- Format data another way -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The site is being hosted on a larger site which doesn't allow its microsites to use any server side scripting so my options are severely limited here.
In such situation I use layouts, each contained in a separate XML document.
The (filename of the) layout to use can be passed as a parameter to the transformation, or it can be dynamically determined within the transformation.
From this moment on, the Layout XML document can be accessed using the XSLT document() function:
<xsl:variable name="vDocLayout" select="document($pLayout)"/>
Then you can issue:
<xsl:apply-templates select="$vDocLayout"/>
This is the "fill in the blanks
" XSLT design pattern.
You could use Client Side XSLT. Provide a PI into your XML documents and in the specific stylesheet include the master layout stylesheet.
Be free to check and use http://www.aranedabienesraices.com.ar as example.
EDIT 3: Almost full example with recursion.
XML document "layoutA.xml":
<html xmlns:inc="include">
<body>
<h1>Birthday</h1>
<dl inc:in-iter="person">
<dt inc:path="name"></dt>
<dd inc:path="date"></dd>
</dl>
</body>
</html>
Input XML document:
<data>
<person>
<name>Bob</name>
<date>2010-02-23</date>
<link>http://example.org/bob</link>
</person>
<person>
<name>Alex</name>
<date>2010-02-23</date>
<link>http://example.org/alex</link>
</person>
</data>
Stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:inc="include">
<xsl:param name="pLayout" select="'layoutA.xml'"/>
<xsl:template match="/">
<xsl:apply-templates select="document($pLayout)/*">
<xsl:with-param name="context" select="*"/>
</xsl:apply-templates>
</xsl:template>
<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="*[@inc:path]">
<xsl:param name="context"/>
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:with-param name="context" select="$context"/>
</xsl:apply-templates>
<xsl:value-of select="$context/*[name()=current()/@inc:path]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@inc:in-iter]" priority="1">
<xsl:param name="context"/>
<xsl:variable name="me" select="."/>
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:with-param name="context" select="$context"/>
</xsl:apply-templates>
<xsl:for-each select="$context/*[name()=current()/@inc:in-iter]">
<xsl:apply-templates select="$me/node()">
<xsl:with-param name="context" select="."/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@inc:out-iter]" priority="1">
<xsl:param name="context"/>
<xsl:variable name="me" select="."/>
<xsl:for-each select="$context/*[name()=current()/@inc:out-iter]">
<xsl:element name="{name($me)}" namespace="{namespace-uri($me)}">
<xsl:apply-templates select="$me/@*|$me/node()">
<xsl:with-param name="context" select="."/>
</xsl:apply-templates>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="@inc:path|@inc:in-iter|@inc:out-iter" priority="1"/>
<xsl:template match="@inc:*">
<xsl:param name="context"/>
<xsl:attribute name="{local-name()}">
<xsl:value-of select="$context/*[name()=current()]"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Output:
<html xmlns:inc="include">
<body>
<h1>Birthday</h1>
<dl>
<dt>Bob</dt>
<dd>2010-02-23</dd>
<dt>Alex</dt>
<dd>2010-02-23</dd>
</dl>
</body>
</html>
Passing param pLayout
as 'layoutB.xml'
, and this "layoutB.xml":
<html xmlns:inc="include">
<body>
<h1>Friends</h1>
<ul>
<li inc:out-iter="person">
<a inc:href="link" inc:path="name"></a>
</li>
</ul>
</body>
</html>
Output:
<html xmlns:inc="include">
<body>
<h1>Friends</h1>
<ul>
<li>
<a href="http://example.org/bob">Bob</a>
</li>
<li>
<a href="http://example.org/alex">Alex</a>
</li>
</ul>
</body>
</html>
Note: The main problem with your requeriment is the same document restriction (so, same document URI, no diferent PI, no diferent layout URI metadata) wich leaves you only to javascript to pass the layout URI param. Until browser support XPath 2.0 fn:document-uri()
so you can parse URL query. Of course, you could use some extension (MSXSL script
, as example) but it would be dificult to make it work cross-browser.
精彩评论