I want to produce an HTML file like this example:
English
En Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc rutrum, eros sit amet ornare faucibus.
Français
Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc rutrum, eros sit amet ornare faucibus.
From the following example XML source, on which I have no control:
<?xml version="1.0" encoding="ISO-8859-1"?>
<content id="">
<header language="en">
<enabled>true</enabled>
<img src="http://i.stack.imgur.com/xGCNw.gif" />
<!-- more header-related elements -->
</header>
<header language="fr">
<enabled>false</enabled>
<img src="" />
<!-- more header-related elements -->
</header>
<html language="en" type="source">
<![CDATA[
<p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
]]>
</html>
<html language="fr" type="source">
<![CDATA[
<p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
]]>
</html>
</content>
So I wrote this XSLT to do it:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h1>English</h1>
<hr/>
<xsl:for-each select="content/header">
<xsl:call-template name="header">
<xsl:with-param name="lang">en</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="content/html">
<xsl:call-template name="html">
<xsl:with-param name="lang">en</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<hr/>
<h1>Français</h1>
<hr/>
<xsl:for-each select="content/header">
<xsl:call-template name="header">
<xsl:with-param name="lang">fr</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="content/html">
<xsl:call-template name="html">
<xsl:with-param name="lang">fr</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="header" match="*">
<xsl:param name='lang'/>
<xsl:if test="current()[@language=$lang]">
<xsl:if test="enabled[normalize-space(text())='true']">
<xsl:call-template name="image"/>
<!-- more header-related elements -->
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="image" match="*">
<xsl:if test="img[not(normalize-space(@src)='')]">
<xsl:copy-of select="img"/>
</xsl:if>
</xsl:template>
<xsl:template name="html" match="*">
<xsl:param name='lang'/>
<xsl:if test="current()[@language=$lang]">
<xsl:value-of select="node()" disable-output-escaping="yes" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
That said, my solution feels very verbose, but seems to enable useful composition and reutilization properties, which are two things very important to me, since I will need to transform lots of XML documents whose structure is similar to this example; and thus, if most of my XSLTs can reuse parts of other XSLTs, this will be very useful.
A few notes of interest:
- Transformation speed is of no importance, although it might be interesting to learn more on this aspect.
- The transformations will never need to handle XML documents which encode more than the 2 example languages (en and fr).
So I would like to learn if my solution looks either anti-idiomatic-or even plain wrong-to you, XSLT wranglers.