Dynamically reusing XSLT templates across XSL files

V

Vince C.

Hi all,

I've created XML documents that are described with a schema. I'm using those
documents to create web pages.

All my web pages contain a fixed header and a variable document part. The
header is the same in each page and is described in an XML document,
"Head.xml". The document part, which is variable in content, is described in
other XML files (e.g. "Document.xml", "Product.xml", "Register.xml").

Following the liquid design way, a web page is always built from "Head.XML"
and (only) one XML document. A page is always made of a succession of DIV
elements that are positioned using CSS. A DIV corresponds to a piece of
information in the schema.

I defined the base structure of a document in a schema and I wanted that
structure to be extensible. Hence I've extended the definition of a document
to fit other requirements (e.g. form submission documents - "Register.xml",
product sheet - "Product.xml").

For instance, static information contain a title and a body text. The title
and the text form the base document in "Document.xml". A product document,
"Product.xml", extends the base document definition to add a list of
packages. Packages are also rendered in HTML as a DIV below the body text.

The XSL templates required to output a page HTML, HEAD, BODY and document
header are placed in an XSL file, "Head.xsl". The XSL templates to output a
document are placed in another XSL file, "Document.xsl". The templates to
output a product are placed in yet another XSL file, "Product.xsl".

How can I reuse those templates given that the template that outputs the
structure of the web page must be called first?

A concrete case: to output the web page for a document, I need to call some
templates in "Head.xsl", plus some other templates in "Document.xsl" that
should be called in-between. If I want to output the page for a product I
have to call the same templates from "Head.xsl", that should in turn call
some templates from "Document.xsl" (to render title and text) and finally
call some templates from "Product.xsl" (to render packaging below the text).

Such an order in calls is required because the template that renders the
structure of a page also renders the HTML and BODY elements. So I have to
call templates dynamically from within "Head.xsl".

Is there a smart(er) way to achieve this?

Thanks for any hint/suggestion.

Vince C.
 
V

Vince C.

Thanks a lot, Colin.

See my comments below.

Colin Mackenzie said:
Hi,

I am not sure I fully understand your requirement but here goes,

why not do as follws

1/ transform the XML using Document.xsl/products.xsl etc as required
depending on the type of page
2/ ensure that BOTH document and product XSL include or import head.xsl (see
xsl:include)
3/ ensure that the match for the root or document element of the XML exists
only in the head.xsl thus
a) when the root/document element is matched the <html<body> elments are
output
b) inside the body tag have an apply-tempaltes (to allow the contents to be
processed by a matched template)
c) when the content is matched (by the appropriate match in the appropraite
stylesheet) the content is output

Does this match your requirement?

Perfectly.

In fact, I took a deeper look to <xsl:import>. As you pointed out, it does
everything I want provided <xsl:apply-templates> is used whenever applicable. I
never used XSL imports before so I made a test with a couple of XML and XSL
files.

I created an XML file with 2 elements: "a" and "b". I then created 2 XSL files:
"A.xsl" and "B.xsl". The former contained a template for element "a" and the
main HTML template, the latter contained only a template for element "b" plus an
import of template "B.xsl". I transformed the XML using "B.xsl" and all
templates were called.

-- Test.xml --
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="B.xsl"?>
<root>
<a>First element</a>
<b>Second element</b>
</root>

-- A.xsl --
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="xsl fo"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:template match="a">
<p>This is element <b>A</b>: <i>"<xsl:value-of select="text()"/>"</i></p>
</xsl:template>

<xsl:template match="/">
<html>
<head>
<title>Dynamic Templates Test Page</title>
</head>
<body>
<xsl:apply-templates select="/root"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

-- B.xsl --
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="xsl fo"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:import href="A.xsl"/>
<xsl:template match="b">
<p>This is element <b>B</b>: <i>"<xsl:value-of select="text()"/>"</i></p>
</xsl:template>
</xsl:stylesheet>

-- Output --
This is element A: "First element"

This is element B: "Second element"
----

Ok, I've clearly discovered (Smirnoff Ice?) the <xsl:import> mechanism... But I
now realize its power: it's as flexible as Object Oriented Programming when you
override classes and create polymorphic containers.

Importing templates is just like deriving classes in C++: you can reuse
templates on documents that you didn't design just by importing the existing
ones into new stylesheets. All you have to do is provide templates for new
elements in the instance file or redefine existing templates.

This gives the same flexibility as deriving classes and overriding member
functions. As you also pointed out the structure of stylesheets and documents is
also important.

To bring a complete solution to my puzzle, I can put a reference to "Head.xml"
in "Document.xsl" using the document() function. If I import "Document.xsl" in
every subsequent stylesheet, everything should be fine.

Thanks a lot for again your help,
Vince C.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top