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.