Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using Names and Matches together in XSL templates, we can choose and apply templates dynamically, based on content provided within the XML being transformed. I've searched for ages on how to do this properly, and a number of sources led me to this solution.
<data>
<datasource>
<section handle="test-section">Test Section</section>
<entry>
<page-path handle="about">/about</page-path>
<page-title handle="about">About</page-title>
<title handle="about-this-company">About This Company</title>
<template>
<item id="2" handle="content" section-handle="page-templates" section-name="Page Templates">Content</item>
</template>
</entry>
</datasource>
</data>
<data>
<datasource>
<section handle="test-section">Test Section</section>
<entry>
<page-path handle="about-history">/about/history</page-path>
<page-title handle="history">History</page-title>
<title handle="the-history-of-this-company">The History of This Company</title>
<template>
<item id="4" handle="article" section-handle="page-templates" section-name="Page Templates">Article</item>
</template>
</entry>
</datasource>
</data>
<data>
<datasource>
<section handle="test-section">Test Section</section>
<entry>
<page-path handle="contact">/contact</page-path>
<page-title handle="contact">Contact</page-title>
<title handle="contact-this-company">Contact This Company</title>
<template>
<item id="3" handle="contact" section-handle="page-templates" section-name="Page Templates">Contact</item>
</template>
</entry>
</datasource>
</data>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--
Create a variable of this document's templates
-->
<xsl:variable name="content-templates" select="document('')/*/xsl:template"/>
<!--
Match on a content node from the XML
-->
<xsl:template match="*[section/@handle = 'test-section']/entry">
<xsl:apply-templates select="$content-templates[@name = current()/template/item/@handle]">
<xsl:with-param name="node" select="."/>
</xsl:apply-templates>
</xsl:template>
<!--
A Template to output content as a 'Content' style page
-->
<xsl:template match="xsl:template[@name='content']" name="content">
<xsl:param name="node"/>
<h1>content template called!</h1>
<h2><xsl:value-of select="$node/page-title/text()"/></h2>
</xsl:template>
<!--
Template to output content as a 'Contact' style page
-->
<xsl:template match="xsl:template[@name='contact']" name="contact">
<xsl:param name="node"/>
<h1>contact template called!</h1>
<h2><xsl:value-of select="$node/page-title/text()"/></h2>
</xsl:template>
</xsl:stylesheet>
@vlad-ghita
Copy link

vlad-ghita commented Feb 13, 2013

Very interesting idea you showed above. Didn't know XSLT is capable of this stuff.

Another way to do it would be to use the mode attribute and the xsl:template match="". Here's how I'm doing similar stuff:

<!-- Match on a content node from the XML -->
<xsl:template match="*[section/@handle = 'test-section']/entry">

    <!-- Create a custom callback using the client supplied template handle -->
    <xsl:variable name="callback">
        <xsl:element name="template_{template/item/@handle}">

            <!-- put here the data you need. In this case, the Entry -->
            <xsl:copy-of select="."/>

        </xsl:element>
    </xsl:variable>

    <!-- just call this callback using a mode to particularize it -->
    <!-- ("mode" is like a Class and node "callback" is like a method) -->
    <xsl:apply-templates select="exsl:node-set($callback)/*/entry" mode="template_callback"/>
</xsl:template>


<!-- A Template to output content as a 'Content' style page -->
<xsl:template match="template_content/entry" mode="template_callback">
    <h1>content template called!</h1>
    <h2>
        <xsl:value-of select="page-title"/>
    </h2>
</xsl:template>


<!-- Template to output content as a 'Contact' style page -->
<xsl:template match="template_contact/entry" mode="template_callback">
    <h1>contact template called!</h1>
    <h2>
        <xsl:value-of select="page-title"/>
    </h2>
</xsl:template>

@designermonkey
Copy link
Author

designermonkey commented Feb 13, 2013

That's really cool too! Nice approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment