Question

Is it possible to use a different HTML layout for the same XSLT stylesheet?

I have been reading up on XSLT and most examples i see show that the HTML code is actually embedded within the stylesheet.

Is it possible to use the same stylesheet for more than one HTML layout? (I am thinking similar to how Velocity works - i.e. multiple HTML files can be processed using the same Velocity tags).

I am using the Java Xalan processor to process the XSLT.

Edit

I have tried @Dimitre Novatchev approach below and it works perfectly. The only thing is how would i handle looping through elements? For example, if the xml document is modified to be:

<person>
 <fname>John</fname>
 <lname>Smith</lname>
 <age>25</age>
 <age>33</age>
 <age>55</age>
</person>

How can i iterate through each of the age elements?

Here is what i tried on the HTML template but i didnt see any difference:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/> <gen:lname/>!</h1>

  You are <gen:age/> years old.  

  <gen:for-each select="/person/age">
    <gen:age/>,
  </gen:for-each>

 </body>
</html>

Expected output

I would like the output of the above to be

Hi JohnSmith!
You are 25 years old. 

25, 33, 55
Was it helpful?

Solution

Yes, this is a very powerful technique, whcih I call "fill-in the blanks".

Here is a very short example:

Skeleton 1:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/>!</h1>
 </body>
</html>

Skeleton 2:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/> <gen:lname/>!</h1>

  You are <gen:age/> years old.
 </body>
</html>

The XSLT transformation is passed as an external parameter the Uri of the "skeleton to use" and it copies all nodes "as-is" with the exception of the specially-named elements (whose names are in the special namespace "my:tranform-generated"). These are substituted by the result of the templates that match them in the XSLT transformation.

Here is an example of such a transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:gen="my:tranform-generated" exclude-result-prefixes="gen">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pSkeleton" select="'file:///c:/temp/delete/Skeleton1.xml'"/>

 <xsl:variable name="vData" select="/"/>

 <xsl:template match="/">
  <xsl:apply-templates select="document($pSkeleton)/*"/>
 </xsl:template>

 <xsl:template match="*">
     <xsl:element name="{name()}">
       <xsl:copy-of select="namespace::*[not(. = 'my:tranform-generated')]"/>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

 <xsl:template match="*[namespace-uri()='my:tranform-generated']">
  <xsl:value-of select="$vData/*/*[name() = local-name(current())]"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on this XML document:

<person>
 <fname>John</fname>
 <lname>Smith</lname>
 <age>25</age>
</person>

the wanted, correct result (using Skeleton1.xml) is produced:

<html>
   <body>
      <h1>Hi John!</h1>
   </body>
</html>

When the same transformation is applied on the same XML document, but the external parameter $pSkeleton passed to it has the value of "file:///c:/temp/delete/Skeleton2.xml", then again we get the wanted result (a formatted Skeleton2):

<html>
   <body>
      <h1>Hi JohnSmith!</h1>

      You are 25 years old.

   </body>
</html>

Update:

Here is an example how to handle iteration -- as requested by the OP:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:gen="my:tranform-generated" exclude-result-prefixes="gen">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pSkeleton" select="'file:///c:/temp/delete/Skeleton3.xml'"/>

 <xsl:variable name="vData" select="/"/>

 <xsl:template match="/">
  <xsl:apply-templates select="document($pSkeleton)/*"/>
 </xsl:template>

 <xsl:template match="*">
     <xsl:element name="{name()}">
       <xsl:copy-of select="namespace::*[not(. = 'my:tranform-generated')]"/>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

 <xsl:template match="*[namespace-uri()='my:tranform-generated']">
  <xsl:value-of select="$vData/*/*[name() = local-name(current())]"/>
 </xsl:template>

 <xsl:template match="gen:context" priority="2">
     <xsl:apply-templates>
       <xsl:with-param name="pContext"
         select="$vData/*/*[name()=current()/@select][1]"/>
     </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="gen:iterate" priority="2">
  <xsl:param name="pContext"/>

  <xsl:variable name="vDelim" select="string(@delimiter)"/>

  <xsl:for-each select="$pContext/*[name()= current()/@select]">
   <xsl:if test="not(position()=1)"><xsl:copy-of select="$vDelim"/></xsl:if>
   <xsl:copy-of select="node()"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

Skeleton3.xml:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/> <gen:lname/>!</h1>

  You are <gen:age/> years old.

  Education:
  <gen:context select="education">
    <gen:iterate select="degree" delimiter=", "/>
  </gen:context>
 </body>
</html>

When the transformation above is applied on the this XML document:

<person>
 <fname>John</fname>
 <lname>Smith</lname>
 <age>25</age>

 <education>
  <degree>MSc. Biology</degree>
  <degree>MBa.</degree>
  <degree>PhD. Computer Science</degree>
 </education>
</person>

the wanted, correct result is produced:

<html>
   <body>
      <h1>Hi JohnSmith!</h1>

      You are 25 years old.

        Education:
        MSc. Biology, MBa., PhD. Computer Science
   </body>
</html>

OTHER TIPS

Yes this is possible. You can surround blocks of html in xsl:if tags

for example:

<xsl:if test="value &gt; 75000"><p>Print out this html</p></xsl:if>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top