<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jakob Külzer &#187; Grails</title>
	<atom:link href="http://www.jakusys.de/blog/tag/grails/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jakusys.de/blog</link>
	<description>Ninja Coding Monkey goes Canada</description>
	<lastBuildDate>Wed, 12 May 2010 00:45:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Building a CMS using XML, XSLT, Ant and ImageMagick</title>
		<link>http://www.jakusys.de/blog/2010/01/building-a-cms-using-xml-xslt-ant-and-imagemagik/</link>
		<comments>http://www.jakusys.de/blog/2010/01/building-a-cms-using-xml-xslt-ant-and-imagemagik/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 12:17:28 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[AIR]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[ImageMagik]]></category>
		<category><![CDATA[Saxon]]></category>
		<category><![CDATA[Webdevelopment]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[XSLT]]></category>
		<category><![CDATA[XSLT2.0]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=1051</guid>
		<description><![CDATA[Not so long ago a freelance client approached me with some updates for their website. The site has been growing organically since 2000 and therefore was a big mess. Several attempts to port the site to a CMS driven system failed largely because those CMS systems are usually to complex for our needs (Typo3) or [...]]]></description>
			<content:encoded><![CDATA[<p>Not so long ago a freelance client approached me with some updates for their website. The site has been growing organically since 2000 and therefore was a big mess. Several attempts to port the site to a CMS driven system failed largely because those CMS systems are usually to complex for our needs (Typo3) or not flexible enough (Joomla, Wordpress). So as I was faced with updates to all the updates including image updates which in turn needed thumbnails to be generated. The same day I stumbled randomly over the <a href="http://www.w3.org/TR/xslt20/" target="_blank">xsl:result-document</a> function in XSLT 2.0 which allows you to transform a single XML file into several output files. That sparked an idea with me: why not use that to build a CMS system using XML technologies? I've toyed around with <a title="Apache Cocoon" href="http://cocoon.apache.org/" target="_blank">Cocoon</a> a couple of years ago but that was not what I was looking for. So I looked for other technologies...</p>
<p>This post is a write-down of my experiences building a XML/XSLT driven simple CMS system. In it I will show you the required technologies, my approaches and my solutions to problems I've encountered. You'll need a solid understanding of XML at least, understanding of Ant and XSLT helps a lot, too.</p>
<p>This post contains tons of XML and I tried my best to format it in a readable way — in fact I've spent hours to get everything nicely on the screen.<br />
<span id="more-1051"></span></p>
<h2>Requirements to the CMS</h2>
<p>I had several objectives when I built my system:</p>
<ul>
<li>All mundane and repetitive tasks should be automated, including thumbnail generation, creation of a global navigation, synchronizing with a live site</li>
<li>Flexible enough to support new "content types" and new views</li>
<li>Versionable with Git, Subversion or other SCMs</li>
<li>Creation of output artifacts should be a single command</li>
</ul>
<h2>Technologies</h2>
<p>The most prominent and important technology I used is XSLT 2.0. If you don't know what XSLT is, here is XSLT in a nutshell.</p>
<p>XSLT stands for eXtensible Stylesheet Language Transformations. What it does is surprisingly simple. It takes a piece of XML as input (aka source tree or input tree), applies some transformations on it and outputs a new piece of XML. Sounds simple in theory, however in practice it is usually somewhat more complicated because XSLT is a functional language and sometimes requires you to solve problems backwards and don't even get me started on <a href="http://www.w3.org/TR/xml-names11/" target="_blank">XML namespaces</a>...</p>
<p>Traditionally you'd have one input XML file, one XSL stylesheet and accordingly one single XML output file. However with the new xsl:result-document I can suddenly output into several files.</p>
<p>As I'm using XSLT the next technology used is XML of course. Not much to say about this except that it is involved in pretty much every step. To bind everything together I'm using <a title="Apache Ant" href="http://ant.apache.org/" target="_blank">Apache Ant</a>, an incredibly flexible tool. Interestingly enough Ant uses XML files for its build files which comes in handy later on. Also it solves one of my requirements: it is just plain text and therefor versionable.</p>
<p>Last there is image manipulation. I've experimented a bit with the Ant image tasks that use JAI to perform manipulation but quickly dropped that approach as this task won't even let you specify a quality parameter for image manipulations. I've ended up using an old friend: <a title="ImageMagick" href="http://www.imagemagick.org/script/index.php" target="_blank">ImageMagick</a>. ImageMagick is an amazing toolkit of versatile command line tools to modify images. It allows to modify images in many different ways from resizing to color correction or combining them.</p>
<h2>Basic Structure</h2>
<p>The basic structure of an XML/XSLT driven CMS contains one or more XML files that contain the "raw" data for the website, XSLT to transform it into XHTML and assets. More on assets later.</p>
<h3>The XML Part</h3>
<p>The XML file used in my project is a very simple one. It defines "pages" that get translated into real HTML pages. Each page has a section called contents which in turn contain the actual page contents. Let's have a look at a short sample:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;utf-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:site</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;My XSLT Generated website&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns:s</span>=<span style="color: #ff0000;">&quot;http://www.jakusys.de/xslt-cms&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Home&quot;</span> <span style="color: #000066;">filename</span>=<span style="color: #ff0000;">&quot;index.html&quot;</span> <span style="color: #000066;">showTitle</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:contents<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Welcome to my XSLT generated page!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Bla bla bla <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:contents<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Contact Me&quot;</span> <span style="color: #000066;">filename</span>=<span style="color: #ff0000;">&quot;contactme.html&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:contents<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Contact Me<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Send me an <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>email<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:contents<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:site<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Well, so far nothing impressive. Actually it looks like more work compared to typing out the actual pages themselves. But behold, here comes the stylesheet to actually turn the above XML into nice websites (XHTML):</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:stylesheet</span> <span style="color: #000066;">xmlns:xsl</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;2.0&quot;</span> <span style="color: #000066;">exclude-result-prefixes</span>=<span style="color: #ff0000;">&quot;#all&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xpath-default-namespace</span>=<span style="color: #ff0000;">&quot;http://www.jakusys.de/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:output</span> <span style="color: #000066;">method</span>=<span style="color: #ff0000;">&quot;html&quot;</span> <span style="color: #000066;">indent</span>=<span style="color: #ff0000;">&quot;yes&quot;</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;html&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">omit-xml-declaration</span>=<span style="color: #ff0000;">&quot;yes&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;site&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;site&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;page&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;page&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:variable</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;filename&quot;</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@filename&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:result-document</span> <span style="color: #000066;">omit-xml-declaration</span>=<span style="color: #ff0000;">&quot;yes&quot;</span> <span style="color: #000066;">indent</span>=<span style="color: #ff0000;">&quot;yes&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;{$filename}&quot;</span> <span style="color: #000066;">format</span>=<span style="color: #ff0000;">&quot;html&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">doctype-public</span>=<span style="color: #ff0000;">&quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">doctype-system</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;Content-Type&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=utf-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:value-of</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@title&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;container&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;contents/*&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:result-document<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;*&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;html&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:copy</span> <span style="color: #000066;">copy-namespaces</span>=<span style="color: #ff0000;">&quot;no&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:copy-of</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@*&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;html&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:copy<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:stylesheet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Now it get's more interesting. Let's dissect what the above XSLT does. The blocks in line 10 to 12 are a template that matches the root level element in the source XML tree. All it does is to call the next matching stylesheets which are in lines 14 to 19. This template does exactly the same and passes on. Then we reach line 18 with the template matching page elements.</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:variable</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;filename&quot;</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@filename&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:result-document</span> <span style="color: #000066;">omit-xml-declaration</span>=<span style="color: #ff0000;">&quot;yes&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; <span style="color: #000066;">indent</span>=<span style="color: #ff0000;">&quot;yes&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;{$filename}&quot;</span> <span style="color: #000066;">format</span>=<span style="color: #ff0000;">&quot;html&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; <span style="color: #000066;">doctype-public</span>=<span style="color: #ff0000;">&quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; <span style="color: #000066;">doctype-system</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span></div></td></tr></tbody></table></div>
<p>Line 18 defines a variable called filename which is prefilled with with the filename attribute from the XML page element. The next line sports the so much praised (at least by me) xsl:result-document element. If you read the line it gets clear very fast that it should output a new HTML file (format="html" href="$filename"), nicely formatted (indent="yes") and with the appropriate DOCTYPE declaration. The  next lines are just an HTML boilerplate with head and content type. Please note that this is a very minimalistic example. Usually you would include stylesheets, JavaScript includes and other additional headers there. For simplicity they are omitted.</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>28<br />29<br />30<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:value-of</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@title&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span> - <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:value-of</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;/site/@title&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Lines 28 to 31 output a new title tag populated with the title attribute from our source attribute. Convenient. The CMS is starting to take shape.</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>33<br />34<br />35<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;container&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;contents/*&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>And finally lines 33 to 35 will call another template lines 41 to 46 which just copies the HTML into the output document.</p>
<p>So far so good. What have we achieved? The stylesheet creates a new page based on boilerplate HTML - which can be arbitrarily complex with CSS stylesheets, JavaScript and more - and pre-fills the title and the actual body. Now let's add more functionality. Every good website needs a navigation. We can achieve that easily by adding another template that matches all page elements. We add a few new lines to the boilerplate HTML:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;navigation&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;/site/page&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;navigation&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Looks simple enough. This will output a new DIV, fill it with a unordered list and calls another template.  The interesting part is the select attribute: it tells the XSLT processor to select all root level page elements. Now let's have a look at how the called template looks like:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;page&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;navigation&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;{@filename}&quot;</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;{@title}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:value-of</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@title&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>The XSLT processor will translate this into global navigation of our site. All top level pages will be listed with the correct title and the correct filename.</p>
<h3>The Ant Part</h3>
<p>Now that we have the stylesheets and the input XML files in place, we'll need an elegant way to transform the whole site with on simple command. As discussed earlier Ant is a good choice for this. I won't delve into the actual ANT buildfile as it is pretty straightforward. What I want to show is how to use XSLT to generate ANT buildfiles from other XML. This is actually a pretty powerful technique as I can custom tailor ANT files to whatever need I have. In this particular example I want to show how to create image thumbnails.</p>
<p>Here is what we have. In our input XML file, we reference images. For those images, let's say, product shots, we have the originals lying in some location in the filesystem. Those images need to be scaled down to a high res view (800×600) and to a thumbnail (128×128). We could do that with an ANT pathmatcher, but that would just take all the images it can find, not just the referenced ones. Bad and slow. And how do we keep the build directory free of old and unused pictures then?</p>
<p>What we'll do instead is we'll take the input XML file, create a XSLT stylesheet that will grab all the image references and put them into a custom ANT build file which in turn calls an image manipulation program (ImageMagick) to scale down the pictures. There's a few other goodies in here too, e.g. automatic file name cleanup. Here is the images.xsl:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:stylesheet</span> <span style="color: #000066;">xmlns:xsl</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;2.0&quot;</span> <span style="color: #000066;">xpath-default-namespace</span>=<span style="color: #ff0000;">&quot;http://www.jakusys.de/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:output</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000066;">method</span>=<span style="color: #ff0000;">&quot;xml&quot;</span> <span style="color: #000066;">indent</span>=<span style="color: #ff0000;">&quot;yes&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;project</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;Image Processing&quot;</span> <span style="color: #000066;">default</span>=<span style="color: #ff0000;">&quot;prepare-images&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;prepare-images&quot;</span> <span style="color: #000066;">depends</span>=<span style="color: #ff0000;">&quot;copy-originals,scale&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;copy-originals&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:element</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;copy&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;todir&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:text<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${build.dir}/images<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:text<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:element</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;fileset&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;dir&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:text<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${assets.dir}/images<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:text<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;//image&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;copy-original&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:element<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:element<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> &nbsp; <br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;scale&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;//image&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;thumbnail&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/project<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;image&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;thumbnail&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;exec</span> <span style="color: #000066;">executable</span>=<span style="color: #ff0000;">&quot;/opt/local/bin/convert&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;arg</span> <span style="color: #000066;">line</span>=<span style="color: #ff0000;">&quot;-thumbnail 128x128 -quality 0.85 assets/images/{@src}.jpg build/images/{lower-case(@src)}_thumb.jpg&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/exec<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;image&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;copy-original&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;include</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;{lower-case(@src)}.jpg&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:stylesheet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<h2>Google Sitemaps</h2>
<p>Most people that have used Google's Webmaster Tools know about the sitemap. No need to write them manually any more, you can easily use the XML representation and a XSLT stylesheet to generate it for you:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:stylesheet</span> <span style="color: #000066;">xmlns:xsl</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;2.0&quot;</span> <span style="color: #000066;">xpath-default-namespace</span>=<span style="color: #ff0000;">&quot;http://www.jakusys.de/&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:output</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000066;">method</span>=<span style="color: #ff0000;">&quot;xml&quot;</span> <span style="color: #000066;">indent</span>=<span style="color: #ff0000;">&quot;yes&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;urlset</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:apply-templates</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;site/page&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/urlset<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:template</span> <span style="color: #000066;">match</span>=<span style="color: #ff0000;">&quot;page&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;loc<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://www.my-website.com/<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;xsl:value-of</span> <span style="color: #000066;">select</span>=<span style="color: #ff0000;">&quot;@filename&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/loc<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lastmod<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>2009-09-10<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lastmod<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;changefreq<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>monthly<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/changefreq<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:template<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/xsl:stylesheet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<h2>Issues</h2>
<p>So with all the technologies in place, I ran into some issues but all of them could be solved quickly. I'm listing them here hoping they'll help other people.</p>
<h3>XSLT 2.0 with Ant</h3>
<p>This one was most annoying. Per default Ant has an <a title="Apache Ant XSLT" href="http://ant.apache.org/manual/CoreTasks/style.html" target="_blank">xslt-task</a> which allows you to transform XML but it is limited to XSLT 1.0. If you read the documentation you'll find out that you can plug in different XSLT processors but you are still quite limited. If you want to use XSLT 2.0 with Ant get the amazing <a title="Saxon XML Processor" href="http://saxon.sourceforge.net/" target="_blank">Saxon processor</a> and use their Ant task which is a bit hidden on their page. Get it from the Sourceforge <a title="Saxon Ant Task" href="http://sourceforge.net/projects/saxon/files/saxon%20ant%20task/" target="_blank">download site</a>. This task lets you leverage the full functionality of XSLT 2.0 including the xsl:result-document.</p>
<p>All you have to do to get it working is to copy the required JARs into the classpath, declare the custom task and use it:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;taskdef</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;saxon-xslt&quot;</span> <span style="color: #000066;">classname</span>=<span style="color: #ff0000;">&quot;net.sf.saxon.ant.AntTransform&quot;</span> </span><br />
<span style="color: #009900;"> &nbsp; <span style="color: #000066;">classpath</span>=<span style="color: #ff0000;">&quot;lib/saxon9he.jar;lib/saxon9-ant.jar&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></td></tr></tbody></table></div>
<p>Now you can use the saxon-xslt task:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;transform&quot;</span> <span style="color: #000066;">depends</span>=<span style="color: #ff0000;">&quot;init&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;saxon-xslt</span> <span style="color: #000066;">in</span>=<span style="color: #ff0000;">&quot;${xml}&quot;</span> <span style="color: #000066;">style</span>=<span style="color: #ff0000;">&quot;${xsl}&quot;</span> <span style="color: #000066;">out</span>=<span style="color: #ff0000;">&quot;${build.dir}/output.html&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<h3>XML Namespaces in HTML</h3>
<p>This was a tricky one. The problem was that in my custom XML I had snippets of HTML which I wanted to mirror into the output documents. I used the xsl:copy-of function which basically did what it was supposed to. It copied the (X)HTML over but by doing so, it had to adjust the namespaces for the XML. The input document had no namespace declarations at all and the output document was bound to the XHTML namespace. So the processor did exactly what it is supposed to: it added null namespace  declarations to the copied elements which looked like this:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;null&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Bla bla bla<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Not a problem per se but unfortunately invalid XHTML. The solution to this problem is surprisingly simple: Add namespace declarations to the input document:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;utf-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:site</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;My XSLT Generated website&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns:s</span>=<span style="color: #ff0000;">&quot;http://www.jakusys.de/xslt-cms&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span></div></td></tr></tbody></table></div>
<p>The above lines will put the input document per default into the XHTML namespace and everything else in my own, personal namespace. Regular (X)HTML markup however does not get any namespace prefixes, so it will be put into the XHTML namespace:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Home&quot;</span> <span style="color: #000066;">filename</span>=<span style="color: #ff0000;">&quot;index.html&quot;</span> <span style="color: #000066;">showTitle</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:contents<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Welcome to my XSLT generated page!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:contents<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/s:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<h2>Conclusion</h2>
<p>The one big problem I still have with this system is that it does not support hierarchical pages yet. But if the need arises it could be added without too much effort. Another moose with the system is that it still requires editing XML which is neither user-friendly nor easy for non technical users. But one could easily create a Flex or AIR app to modify and edit those files. Thanks to Flex' really good XML support it should not be hard to do that. I could even think of a Grails Webapp generating the XML for this (using the brilliant XML markup builder).</p>
<p>In general it is a really powerful and flexible system. As I am running this on a UNIX system I can harness all the tools and goodies that are there. Ant and Java give me whatever power and libraries I need. So I can steer this thing in whichever direction I want.</p>
<p>If you have any questions feel free to comment below or drop me an email.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2010/01/building-a-cms-using-xml-xslt-ant-and-imagemagik/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Liquibase Incremental DB Diff</title>
		<link>http://www.jakusys.de/blog/2009/12/liquibase-incremental-db-diff/</link>
		<comments>http://www.jakusys.de/blog/2009/12/liquibase-incremental-db-diff/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 15:14:24 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[#ggx]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Groovy & Grails Exchange]]></category>
		<category><![CDATA[LiquiBase]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Schema]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=1112</guid>
		<description><![CDATA[After discussing this on the Groovy and Grails Exchange, I finally put together a new version of the db diff script that I've mentioned in an earlier post. I couldn't find the original version that I've written a couple of months ago, so I hacked together a new one. It's far from perfect, efficient or [...]]]></description>
			<content:encoded><![CDATA[<p>After discussing this on the Groovy and Grails Exchange, I finally put together a new version of the db diff script that I've mentioned in an earlier post. I couldn't find the original version that I've written a couple of months ago, so I hacked together a new one. It's far from perfect, efficient or beautiful, but it does what it is supposed to.</p>
<p>So, what's the idea behind this script? Everybody that uses Liquibase (if you are not, check out my blog post about <a title="Liqiubase and Grails - How to use it" href="http://www.jakusys.de/blog/2008/09/grails-and-liquibase-how-to-use/" target="_blank">what Liquibase is and how to use it</a>) knows how painful it is to update your changelog.xml. Liquibase already gives you a great tool to start with, the db-diff command. However, it is hardcoded to diff the current environment's database against the test database. This is annoying as you'll have to modify your datasources and keep the database schema updated manually. But fear not, here is my (surprisingly) easy solution.</p>
<p>I've created a simple script (or rather, I took the db-diff script and hacked it), which I've called incremental DB diff (all the other cool names are already taken...) and what it does is the following:</p>
<ol>
<li> update the schema in the db-diff (or whatever you call it) database using the changelog.xml</li>
<li>diff the database of the current environment against this database and output the diff as Liquibase XML</li>
</ol>
<p>So, how is this a good thing? Easy: this little script will automatically create a target database to diff against using the changelog.xml which is good, as the changelog.xml represents your last migration status. And as it uses a separate database it doesn't influence the test database.</p>
<p>After running the script just put the output in the changelog.xml and you're done.</p>
<p>All you have to do to use this is to drop the file into your /scripts/ directory, create a new database and an according datasource entry for the environment "dbdiff" like this:</p>
<pre>	dbdiff {
		dataSource {
			driverClassName = "com.mysql.jdbc.Driver"
			dbCreate = "create-drop"
			url = "jdbc:mysql://localhost/foo_dbdiff"
			username = "foo"
			password = "bar"
		}
	}</pre>
<p>Download <a href="http://www.jakusys.de/files/DbDiffIncremental.groovy" target="_blank">DbDiffIncremental.groovy</a>. Drop me a mail or a comment if you have questions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2009/12/liquibase-incremental-db-diff/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Grails GraniteDS Plugin and Flex Modules &#8211; Could not resolve ? to a component implementation</title>
		<link>http://www.jakusys.de/blog/2009/10/grails-graniteds-plugin-and-flex-modules-could-not-resolve-to-a-component-implementation/</link>
		<comments>http://www.jakusys.de/blog/2009/10/grails-graniteds-plugin-and-flex-modules-could-not-resolve-to-a-component-implementation/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 19:30:00 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Flex Modules]]></category>
		<category><![CDATA[Gotcha]]></category>
		<category><![CDATA[GraniteDS]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=1107</guid>
		<description><![CDATA[I'm currently working a lot with the Grails GraniteDS plugin. Just recently I've started to separate my application into modules and ran into a really nasty error.
It took me some time to figure it out, hopefully I can save you from going through all this.
The Flex web tier compiler usually gives me this error:
Error: Could [...]]]></description>
			<content:encoded><![CDATA[<p>I'm currently working a lot with the Grails GraniteDS plugin. Just recently I've started to separate my application into modules and ran into a really nasty error.</p>
<p>It took me some time to figure it out, hopefully I can save you from going through all this.</p>
<p>The Flex web tier compiler usually gives me this error:</p>
<pre>Error: Could not resolve &lt;namespace:Component&gt; to a component implementation.

 &lt;namespace:Component/&gt;

error during compilation Could not resolve &lt;namespace:Component&gt; to a component implementation.</pre>
<p>Initial research confirmed what I thought, this error is caused by a mismatch between a XML namespace declaration and the actual location of a component. However the location and the namespace declaration looked right and the issue occurred only <strong>after</strong> I had moved the questionable component into a separate module.</p>
<p>After two painful hours I realized that the Flex webtier compiler, as configured with GraniteDS, <strong>resolves namespaces relative to modules, not relative to the source folder</strong>. D'oh!</p>
<p>The solution I came up with was simple, might be naïve though. I figured that if resolution is relative to the Module and not to the source folder, there might be no such source folder as I would expect it. A quick look into the flex-config.xml found in &lt;GRAILS_PROJ&gt;/web-app/WEB-INF/flex/flex-config.xml confirmed this:</p>
<pre>&lt;!-- List of path elements that form the roots of ActionScript class hierarchies. --&gt;
<strong> &lt;!-- not set --&gt;</strong>
 &lt;!--
 &lt;source-path&gt;
 &lt;path-element&gt;string&lt;/path-element&gt;
 &lt;/source-path&gt;
 --&gt;</pre>
<p>So there is no explicit source path set. So I changed it so it would point to &lt;GRAILS_PROJ&gt;/grails-app/views/flex:</p>
<pre>&lt;!-- List of path elements that form the roots of ActionScript class hierarchies. --&gt;
 &lt;!-- not set --&gt;
 &lt;source-path&gt;
<strong> &lt;path-element&gt;../../../grails-app/views/flex&lt;/path-element&gt;</strong>
 &lt;/source-path&gt;</pre>
<p>Voilá - it works. However, as mentioned earlier, this might be a very limited solution, but for now it works.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2009/10/grails-graniteds-plugin-and-flex-modules-could-not-resolve-to-a-component-implementation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preakness.com launches on Grails</title>
		<link>http://www.jakusys.de/blog/2009/04/preaknesscom-launches-on-grails/</link>
		<comments>http://www.jakusys.de/blog/2009/04/preaknesscom-launches-on-grails/#comments</comments>
		<pubDate>Wed, 15 Apr 2009 22:57:10 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[GoogleMaps]]></category>
		<category><![CDATA[Launch]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=953</guid>
		<description><![CDATA[Today we launched the new Preakness 134 site based on Grails. Yeay. Check it out.
]]></description>
			<content:encoded><![CDATA[<p>Today we launched the new Preakness 134 site based on Grails. Yeay. <a href="http://www.preakness.com/" target="_blank">Check it out</a>.</p>
<div id="attachment_917" class="wp-caption alignnone" style="width: 160px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2009/04/picture-10.jpg" rel="lightbox[953]"><img class="size-thumbnail wp-image-917" title="The Preakness Landing Site" src="http://www.jakusys.de/blog/wp-content/uploads/2009/04/picture-10-150x150.jpg" alt="The Preakness Landing Site" width="150" height="150" /></a><p class="wp-caption-text">The Preakness Landing Site</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2009/04/preaknesscom-launches-on-grails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>refundroadtrip.ca goes live on Grails</title>
		<link>http://www.jakusys.de/blog/2009/02/refundroadtripca-goes-live-on-grails/</link>
		<comments>http://www.jakusys.de/blog/2009/02/refundroadtripca-goes-live-on-grails/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 04:13:08 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[GoogleMaps]]></category>
		<category><![CDATA[YouTube]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=805</guid>
		<description><![CDATA[Ok, I'm a bit late on this but I've been quite busy the last weeks. Tomás already blogged about this quite some time ago but now I want to showcase what we did as there is a lot of interesting technology in there. The page we built is live on http://www.refundroadtrip.ca/ and sports an interesting [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, I'm a bit late on this but I've been quite busy the last weeks. <a title="Tomás Lin: Refundroadtrip.ca " href="http://fbflex.wordpress.com/2009/02/06/refundroadtripca-launches-on-grails-and-ajax/" target="_blank">Tomás already blogged about this</a> quite some time ago but now I want to showcase what we did as there is a lot of interesting technology in there. The page we built is live on <a title="Refundroadtrip.ca" href="http://www.refundroadtrip.ca/" target="_blank">http://www.refundroadtrip.ca/</a> and sports an interesting Google Maps mashup and YouTube integration.</p>

<a href='http://www.jakusys.de/blog/2009/02/refundroadtripca-goes-live-on-grails/picture-4/' title='Refundroadtrip.ca Homepage'><img width="150" height="150" src="http://www.jakusys.de/blog/wp-content/uploads/2009/02/picture-4-150x150.png" class="attachment-thumbnail" alt="Refundroadtrip.ca Homepage" title="Refundroadtrip.ca Homepage" /></a>
<a href='http://www.jakusys.de/blog/2009/02/refundroadtripca-goes-live-on-grails/picture-6/' title='refundroadtrip.ca Road Trips Lander'><img width="150" height="150" src="http://www.jakusys.de/blog/wp-content/uploads/2009/02/picture-6-150x150.png" class="attachment-thumbnail" alt="refundroadtrip.ca Road Trips Lander" title="refundroadtrip.ca Road Trips Lander" /></a>
<a href='http://www.jakusys.de/blog/2009/02/refundroadtripca-goes-live-on-grails/picture-7/' title='refundroadtrip.ca Road Trip Details Page'><img width="150" height="150" src="http://www.jakusys.de/blog/wp-content/uploads/2009/02/picture-7-150x150.png" class="attachment-thumbnail" alt="refundroadtrip.ca Road Trip Details Page" title="refundroadtrip.ca Road Trip Details Page" /></a>

<p>At this point I want to thank all the great people that worked so hard with me to get this project done.</p>
<p>Thank you.</p>
<p>If I find some time I will blog about my experiences integrating all those technologies. Might be some time though.</p>
<p>Update 19/02/2009: We made it to the <a title="Marketing Mag" href="http://www.marketingmag.ca/english/news/marketer/article.jsp?content=20090218_170655_50448" target="_blank">Marketing Mag</a>! Yeay!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2009/02/refundroadtripca-goes-live-on-grails/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Grails Scaffolding In-Depth</title>
		<link>http://www.jakusys.de/blog/2008/12/grails-scaffolding-in-depth/</link>
		<comments>http://www.jakusys.de/blog/2008/12/grails-scaffolding-in-depth/#comments</comments>
		<pubDate>Thu, 11 Dec 2008 15:12:51 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[Scaffolding]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=487</guid>
		<description><![CDATA[Much of Grails power and ability to crank out applications can be accounted to its scaffolding mechanism for creating CRUD interfaces within no time. However, the default scaffolding templates provide only a simple boilerplate and fail to convince for more sophisticated forms. I spent quite some time in the previous weeks writing scaffolding templates. A [...]]]></description>
			<content:encoded><![CDATA[<p>Much of Grails power and ability to crank out applications can be accounted to its scaffolding mechanism for creating <a title="Wikipedia: CRUD" href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete" target="_blank">CRUD</a> interfaces within no time. However, the default scaffolding templates provide only a simple boilerplate and fail to convince for more sophisticated forms. I spent quite some time in the previous weeks writing scaffolding templates. A lot of this process was trial and error, browsing source code and bothering <a title="Tomás Lin's Blog about Flex &amp; Grails" href="http://fbflex.wordpress.com/" target="_blank">Tomás Lin</a>. I still have to find good documentation on this, so I'm posting my findings here in the hope to help people leveraging Grails even more. If you are just trying to understand how scaffolding works to building something more advanced, this is for you.</p>
<p><span id="more-487"></span></p>
<h2>Scaffolding in a Nutshell</h2>
<p>I assume that you know what Grails and its scaffolding mechanism is about, but I'll just summarize it here.</p>
<p>In a nutshell scaffolding is Grails ability to create controllers and views for domain classes. It analyzes the structure of the domain objects and creates all the files and logic required for simple CRUD functionality. If you have some domain classes all you have to do is type the following from within your project directory:</p>
<pre>$ grails generate-all</pre>
<p>This will create controllers and views for all domain classes found. Note that there are generate-views and generate-controller commands as well.</p>
<p>However you'll soon find out that the default templates which are used to create all the files may not fit your needs. Grails offers a separate <a title="Grails install-template" href="http://grails.org/doc/1.0.x/ref/Command%20Line/install-templates.html" target="_blank">command to copy the default templates</a> into your project directory:</p>
<pre>$ grails install-templates</pre>
<p>This will create a new folder src/templates in your project, holding an copy of the default templates, all yours to modify and adapt.</p>
<h2>Grails Scaffolding Templates</h2>
<p>Before we dive into the details of scaffolding, you need to understand the different templates and what they are for. Running the install-templates command will give you the following files withing your project directory:</p>
<pre>src/templates
|-- artifacts
|   |-- Controller.groovy
|   |-- DomainClass.groovy
|   |-- Script.groovy
|   |-- Service.groovy
|   |-- TagLib.groovy
|   |-- Tests.groovy
|   `-- WebTest.groovy
|-- scaffolding
|   |-- <span style="color: #000000;"><strong>Controller.groovy</strong></span>
|   |-- <strong>create.gsp</strong>
|   |-- <strong>edit.gsp</strong>
|   |-- <strong>list.gsp</strong>
|   |-- <strong>renderEditor.template</strong>
|   `-- <strong>show.gsp</strong>
`-- war
    `-- web.xml</pre>
<p>The files relevant for the scaffolding process are in the scaffolding directory and have been highlighted with <span style="color: #000000;"><strong>bold font</strong></span>. So, what are those files for? Let's examine them one by one.</p>
<p>The first one is <strong>Controller.groovy</strong>. This file is used to create the controllers for your domain classes. The syntax in this file may appear a bit weird in the beginning but after all it's just a <a title="Groovy Templates" href="http://groovy.codehaus.org/Groovy+Templates" target="_blank">groovy template</a> (I really encourage you to read this!). With this in mind reading the templates gets very easy. In the Controller.groovy you basically will find all the actions you would expect from your scaffolded controllers and some groovy template markup.</p>
<p>Next are the GSP files, <strong>create.gsp</strong>, <strong>edit.gsp</strong>, <strong>list.gsp</strong> and <strong>show.gsp</strong>. Those are obviously used to render the GSP markup required for your CRUD views. At a first glance lots of magic happen in those files. We'll cover the details in just a minute.</p>
<p>Finally there is the <strong>renderEditor.template</strong>. This file is used when rendering the HTML forms. Basically what happens in here is a translation of a type like Date or byte[] to their according form elements like a date picker or a file upload button.</p>
<h2>The Scaffolding Process</h2>
<p>Alright, so what happens when you issue generate-all for a domain class? There are a couple of players involved in this game. As most obvious besides the templates we just saw there are the actual scripts,  generate-all, generate-views or generate-controller which reside under $GRAILS_HOME/scripts. These scripts instantiate a DefaultGrailsTemplateGenerator which basically is a wrapper around Groovy's <a title="Groovy Template" href="http://groovy.codehaus.org/api/groovy/text/Template.html" target="_blank">Template</a> and <a title="Groovy TemplateEngine" href="http://groovy.codehaus.org/api/groovy/text/TemplateEngine.html" target="_blank">TemplateEngine</a> and binds together all the pieces we've encountered so far. You won't find any Javadocs about this class, so you'll have to browse the Grails sourcecode if you're interested. The DefaultGrailsTemplateGenerator then calls the actual templates.</p>
<p>One key aspect for creating really powerful scaffolding code is to understand what is handed into the templates by the DefaultGrailsTemplateGenerator. It took me quite some time and some source code browsing to figure this out. First there is a variable called propertyName. There isn't anything magical about it, just the name for a variable. However you will encounter this variable all over the templates. For example if scaffolding is run for a class called "User" propertyName would be "user" (note the lower case "u") and all variables of type "User" would be called "user" in the scaffolded output.</p>
<p>Then there is an instance of <a title="Grails DefaultGrailsDomainClass" href="http://grails.org/doc/1.0.3/api/org/codehaus/groovy/grails/commons/GrailsDomainClass.html" target="_blank">DefaultGrailsDomainClass</a> which is handed into the template as a variable called <strong>domainClass</strong>. This class variable plays a major role in scaffolding as it allows you to access all kinds of information about the domain class the scaffolding process is handling. You can get information about the GORM mappings, the associations the class has and even the other side of the associations, which is crucial when building more complex forms and more. And yes, i really encourage you to read the Javadocs for this class.</p>
<p>Depending on whether views or controllers are generated either the create.gsp, list.gsp, edit.gsp and show.gsp or Controller.groovy are used as template.</p>
<h3>Generating a Controller</h3>
<p>When generating controllers the Controller.groovy file is used as template. What you will end up with is a new file named after your Class containing the usual actions required for CRUD. There is not much magic happening in here; the template is pretty straight forward and just creates calls for the different GORM methods. Read it to get a feeling for this.</p>
<h3>Generating Views</h3>
<p>However when generating views, things get more interesting. In the views and the renderEditor.template the domainClass property is actually used to determine information about collections.</p>
<p>So let's dive into the details of how the views are generated. If you look at the templates you'll see that all of them create a list of properties available for a domain class by querying the domainClass variable:</p>
<pre>props = domainClass.properties.findAll { !excludedProps.contains(it.name) }</pre>
<p>All that remains to do now is to iterate over those properties, determine whether they should be visible and call the renderEditor to actually render the required code. The following block of code has been copied from the edit template and has been commented by me to clarify:</p>
<pre>props.each { p -&gt;
    cp = domainClass.constrainedProperties[p.name]
    display = (cp ? cp.display : true) <strong>// Determine visibility</strong>
    if(display) { %&gt;
    &lt;tr class="prop"&gt;
        &lt;td valign="top" class="name"&gt;
            &lt;label for="${p.name}"&gt;${p.naturalName}:&lt;/label&gt;
        &lt;/td&gt;
        &lt;td valign="top" class="value \${hasErrors(bean:${domainClass.propertyName},field:'${p.name}','errors')}"&gt;
            ${renderEditor(p)}  <strong>// Call render editor to render correct form element</strong>
        &lt;/td&gt;
    &lt;/tr&gt;</pre>
<p>This is basically what happens in all the templates. A list of properties is generated and iterated over. One piece is still missing: the renderEditor.template.</p>
<p>As stated earlier, the renderEditor.template translates the type of a property into the appropriate form control. The way this happens is disappointingly simple; open up the file in your favorite editor and you will find a big block of if-statements like this:</p>
<pre>&lt;%  if(property.type == Boolean.class || property.type == boolean.class)
        out &lt;&lt; renderBooleanEditor(domainClass,property)
    else if(Number.class.isAssignableFrom(property.type) || (property.type.isPrimitive() &amp;&amp; property.type != boolean.class))
        out &lt;&lt; renderNumberEditor(domainClass,property)
    else if(property.type == String.class)
        out &lt;&lt; renderStringEditor(domainClass,property)
    else if(property.type == Date.class || property.type == java.sql.Date.class || property.type == java.sql.Time.class)
        out &lt;&lt; renderDateEditor(domainClass,property)
...</pre>
<p>and further below the methods called by the if-statements:</p>
<pre>...
    private renderByteArrayEditor(domainClass,property) {
        return "&lt;input type=\"file\" id=\"${property.name}\" name=\"${property.name}\" /&gt;"
    }

    private renderManyToOne(domainClass,property) {
        if(property.association) {
            return "&lt;g:select optionKey=\"id\" from=\"\${${property.type.name}.list()}\" name=\"${property.name}.id\" value=\"\${${domainClass.propertyName}?.${property.name}?.id}\" ${renderNoSelection(property)}&gt;&lt;/g:select&gt;"
        }
    }
...</pre>
<p>So in the rendering process for each property the type will be matched in the if statements and the appropriate function is called to render out some HTML/GSP code.</p>
<h2>Conclusion</h2>
<p>Creating scaffolding templates is not hard. It requires some knowledge about the involved technologies and concepts but I hope this post gives you a fair understanding of what is going on. If you still have any questions, feel free to comment or drop me an email.</p>
<p>As always, comments are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/12/grails-scaffolding-in-depth/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>LiquiBase, addForeignKeyConstraint and Column Types do not Match</title>
		<link>http://www.jakusys.de/blog/2008/09/liquibase-addforeignkeyconstraint-column-types-do-not-match/</link>
		<comments>http://www.jakusys.de/blog/2008/09/liquibase-addforeignkeyconstraint-column-types-do-not-match/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 02:49:50 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[LiquiBase]]></category>
		<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=367</guid>
		<description><![CDATA[Today I encountered some weird errors while migrating my database using LiquiBase. It took me quite some time to figure out what was wrong as no one has encountered this error before. So, here's the problem and the solution.  
Ugly but simple example: I have two domain classes, say Book and Author and a [...]]]></description>
			<content:encoded><![CDATA[<p>Today I encountered some weird errors while migrating my database using <a title="LiquiBase" href="http://www.liquibase.org/" target="_blank">LiquiBase</a>. It took me quite some time to figure out what was wrong as no one has encountered this error before. So, here's the problem and the solution. <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Ugly but simple example: I have two domain classes, say Book and Author and a Book has an Author. How Author looks like is not important. Book looks like this</p>
<pre>class Book {
  Author author
}</pre>
<p>Due to changes in the requirements the author needs to be optional thus nullable. With updated constraints the Book class looks like this:</p>
<pre>class Book {
  Author author
  static constraints = { author(nullable:true) }
}</pre>
<p>So upgrading the database with LiquiBase should be as easy as adding a couple of lines to the changelog file:</p>
<pre>&lt;changeSet author="jakob" id="foo-1"&gt;
  &lt;dropForeignKeyConstraint baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"/&gt;
  &lt;dropNotNullConstraint tableName="BOOK" columnName="AUTHOR_ID"/&gt;
  &lt;addForeignKeyConstraint baseColumnNames="AUTHOR_ID"
    baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"
    deferrable="false" initiallyDeferred="false"
    referencedColumnNames="ID" referencedTableName="AUTHOR"/&gt;
&lt;/changeSet&gt;</pre>
<p>Basically this changeset drops the foreign key constraint on AUTHOR_ID, drops the not-null-constraints and re-adds the foreign key constraint which is required to handle the association between the Book and the Author class.</p>
<p>Unfortunately the <a title="LiquiBase: addForeignKeyConstraint" href="http://www.liquibase.org/manual/add_foreign_key_constraint" target="_blank">addForeignKeyConstraint</a> will cause an error, something like this:</p>
<pre>Caused by: java.sql.SQLException: Column types do not match in statement [ALTER TABLE...</pre>
<p>The reason why this happens is that: when dropping the not-null constraint the type of the AUTHOR_ID column is re-set to something unusable. Inspecting the database with the HSQLDB Databasemanager showed that the type of the is set to NULL which is weird. The solution to this is easy however. All you need to do is to provide LiquiBase the type with the columnDataType attribute of the column in the <a title="LiquiBase: dropNotNullConstraint" href="http://www.liquibase.org/manual/remove_not-null_constraint" target="_blank">dropNotNullConstraint</a> element:</p>
<pre>&lt;changeSet author="jakob" id="foo-1"&gt;
  &lt;dropForeignKeyConstraint baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"/&gt;
  &lt;dropNotNullConstraint tableName="BOOK" columnName="AUTHOR_ID"/&gt;
  &lt;addForeignKeyConstraint baseColumnNames="AUTHOR_ID" <strong>columnDataType="BIGINT" </strong>
    baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"
    deferrable="false" initiallyDeferred="false"
    referencedColumnNames="ID" referencedTableName="AUTHOR"/&gt;
&lt;/changeSet&gt;</pre>
<p>With this in place it will work like a charm.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/09/liquibase-addforeignkeyconstraint-column-types-do-not-match/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Updated Post about Grails and LiquiBase</title>
		<link>http://www.jakusys.de/blog/2008/09/updated-post-about-grails-and-liquibase/</link>
		<comments>http://www.jakusys.de/blog/2008/09/updated-post-about-grails-and-liquibase/#comments</comments>
		<pubDate>Tue, 23 Sep 2008 03:10:22 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[LiquiBase]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=364</guid>
		<description><![CDATA[If you have read my post about Grails and LiquiBase please note that I updated it today. I added new contents and corrected the section about db-diff. Make sure you have a look at it  .
]]></description>
			<content:encoded><![CDATA[<p>If you have read my <a title="Grails and LiquiBase -- How to Use" href="http://www.jakusys.de/blog/2008/09/grails-and-liquibase-how-to-use/" target="_self">post about Grails and LiquiBase</a> please note that I updated it today. I added new contents and corrected the section about db-diff. Make sure you have a look at it <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/09/updated-post-about-grails-and-liquibase/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Grails and LiquiBase &#8211; How to use</title>
		<link>http://www.jakusys.de/blog/2008/09/grails-and-liquibase-how-to-use/</link>
		<comments>http://www.jakusys.de/blog/2008/09/grails-and-liquibase-how-to-use/#comments</comments>
		<pubDate>Fri, 19 Sep 2008 03:07:51 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[LiquiBase]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=313</guid>
		<description><![CDATA[In my current project I'm now at a point where the application has come pretty far but is still far from finished. The domain model is not perfect, but very stable at this point -- changes however, are still possible.
To get going with the application we are planning to perform tests with some real data. [...]]]></description>
			<content:encoded><![CDATA[<p>In my current project I'm now at a point where the application has come pretty far but is still far from finished. The domain model is not perfect, but very stable at this point -- changes however, are still possible.</p>
<p>To get going with the application we are planning to perform tests with some real data. The problem at this point is that entering real data into a database that might be wiped due to changes in the domain model is a very tedious task, at least for the person responsible for entering the data. And the reason for running such a test is to find problems with the domain model which lead to the dreaded changes in the domain model. This cat bites her own tail...</p>
<p>As wiping out the database and re-entering the data is not an option at this point, I decided to look into <a title="LiquiBase" href="http://www.liquibase.org/home" target="_blank">LiquiBase</a> which as been sitting on my delicious list for quite a while.</p>
<p>This post is an attempt to write down my experiences and learned lessons with LiquiBase. The <a title="LiquiBase Manual" href="http://www.liquibase.org/manual/home" target="_blank">documentation of LiquiBase</a> is technically complete and extensive but lacks more information about how to use it in a real project. This is an attempt to create a guide on how to leverage LiquiBase in a real world project.</p>
<p><span id="more-313"></span></p>
<h2>What is this LiquiBase anyways?</h2>
<p>For starters LiquiBase is a tool that helps developers to track and apply changes to database schemas. Basically what it does is storing all changes that are made to a database in a special XML file, called a database changelog file. This changelog file can be used to determine if there are any changes between the schema in the changelog file and the schema found in a database. The nice thing about LiquiBase is that it is database neutral so you can use with any database Java is able to connect to, and that are a lot...</p>
<p>But there is more to LiquiBase that just tracking changes. The outstanding feature of LiquiBase is that it is able to migrate data using the information stored in the database changelog file. This doesn't sound like very much when you are starting a project from scratch, but as soon as you start entering data in your evolving application, you'll understand. And as every application evolves, this is a feature handy for every developer, especially for Grails developers as Hibernate as ORM basically supports only two modes of operation to handle the database schema (configured via the <tt class="literal"><a title="Hibernate Configuration" href="http://www.hibernate.org/hib_docs/v3/reference/en-US/html/configuration-optional.html" target="_blank">hibernate.hbm2ddl.auto</a> option</tt>): wiping out the database and applying a new schema (called create or create-drop) or attempting to update the schema (simply called update). The update option looks like a good way to go at first but as it turns out it has its drawbacks, especially if there is data in the database.</p>
<h2>How does it work?</h2>
<p>The hub of all activity in LiquiBase is the changelog file. Basically there are two possible ways to create and maintain the changelogs, the first is to use the generated changelogs as far as possible and the other is to write changelogs by hand. I'm sticking mostly to the first one as the generated changelogs are sufficient most of the time and writing changelogs manually is way to tedious though easy as there is a complete XSD.</p>
<p>Each entry in the changelog file is called a changeset and has a unique id. The id is used to refer to specific datasets. But how does LiquiBase know which changesets have been applied to the database? The answer is simple, it creates a table called DATABASECHANGELOG into which it will insert a row for each applied changeset. So make sure you start using LiquiBase early because you really want to have these tables in your database when changes have been incorporated into a running system.</p>
<p>Applying changesets against the database is called migration but more on this later.</p>
<h2>Setting the Scene</h2>
<p>The work flow to push in changes may depend on your project. The work flow I'm describing can be applied to team of couple of Grails developers and has been tested on a real world project.</p>
<p>As an example for the rest of the post let's assume a project that is developed by a couple of code monkeys. The change the domain classes and to monkey stuff. On the other hand there is a data entry system deployed so real data can be inserted into the database and the software can be demoed. I will refer to this system as the demo system. The demo system and the data entered into it has several purposes. First to see if the domain model is adequate for real data and second to provide the developers with real testing data.</p>
<p>Problems arise quickly in this scenario, for example changes are made to the domain model and the database schema of the demo system must be updated, preferably without wiping out all the data that has been entered. At this point LiquiBase comes in.</p>
<h2>Grails and LiquiBase - Getting Started</h2>
<p>Ok, now how to use LiquiBase in a Grails Project? Easy: there is a <a title="Grails LiquiBase Plugin" href="http://www.liquibase.org/manual/grails" target="_blank">LiquiBase grails plugin</a> for grails which can easily be installed using the following command:</p>
<pre>grails install-plugin liquibase</pre>
<p>This will install a copy of LiquiBase in your application and set up a <a title="Grails LiquiBase Commands" href="http://www.liquibase.org/manual/grails" target="_blank">couple of new commands</a> for the grails command line interface. Before you can do anything useful with LiquiBase you have to create a database changelog file for your current database, preferably using the generate-changelog command:</p>
<pre>grails generate-changelog grails-app/migrations/changelog.xml</pre>
<p>Note: if you omit the filename the changelog will be dumped to the console. You can dump the changelog into any file but grails-app/migrations/changelog.xml is the default and LiquiBase will keep looking for this file. With the changelog file in place you should add it to your version control system.</p>
<h2>Tracking Changes</h2>
<p>So the next step is to make some changes to the domain model which result in a change of the database schema. You now have two possibilities for updating your changelog file. Either manually or using some of the neat tools LiquiBase offers. I won't go into the details for creating the files manually, the LiquiBase manual does a good job at this. So let's talk about the tools.</p>
<p>LiquiBase ships with a very powerful command: diff. What this does is it looks at the current database and at <span style="text-decoration: line-through;">the changelog</span> (<strong>I have to correct myself here, see next section! Sorry about this!</strong>) another database and outputs the difference between them. As LiquiBase changelog XML! So this is awesome because you can make changes to your Grails domain model, run it against a database and pull out the changes. All that is then to do is to add the newly generated changesets to your database changelog file.</p>
<h2>The db-diff Tool</h2>
<p>The db-diff tool in the Grails plugin is kind of mysterious. The LiquiBase documentation for the Grails plugin does not even mention it and I got it wrong in the first run. I had to reading the <a title="DB DIFF " href="http://www.liquibase.org/manual/diff" target="_blank">section about the database diff</a> provided by LiquiBase and dig through the Groovy scripts of the LiquiBase Grails plugin to understand what it does.</p>
<p>The diff utility of LiquiBase compares two databases with each other, which kind of explains its name (doh). When using the LiquiBase command line interface you have to provide two different connection strings for two databases. When using the Grails plugin however, you cannot specify two databases (not yet?); so what happens is that: the database for the current environment ist compared to the database of the test environment. This behaviour is hardcoded into plugins/liquibase-1.8.0.0/scripts/DbDiff.groovy and limits the usefulness of the tool. So what I did is every time a database has been migrated the new schema gets propagated to the testing database. If the domain model changes the schema of the dev database, the changes can easily be determined by diff'ing it against the testing database.</p>
<p>This is not exactly a perfect solution as you manually have to keep the testing database in sync with the changelog. So I am currently playing around with a modification of the Grails LiquiBase plugin which adds a compareToChangelog command which populates a separate database from the current changelog and then compares this to the database of the currently used environment. Using this tool makes updating the changelog really easy as you get the changesets just for those changes you made to the domain model. If there is interest I will publish this to the LiquiBase plugin.</p>
<h2>Migrating a Database</h2>
<p>Finally your changelog has been updated and you now need to update your demo database. The first thing you should do: <strong><span style="color: #ff0000;">Make a backup of your database</span></strong>! Although LiquiBase has matured to some extent, migrating a database full of data is a risky endeavor. So make sure you are on the safe side before touching a database with real data.</p>
<p>The easiest way to migrate the database is to set up a copy of your project and modify the datasource to point at the demo database. The first thing you might want to do is to check which changesets have to be executed by running the following command:</p>
<pre>grails status</pre>
<p>This will generate a list of changesets which have to be applied, assuming there is a DATABASECHANGELOG table in the database. If you are happy with what you see, you can either migrate the database directly or do a dry run. I prefer to do a dry run before touching the database by running:</p>
<pre>grails migrate-sql</pre>
<p>This will output a sequence of SQL statements that LiquiBase will issue to migrate the database. This is quite handy as you can see what will happen. Then, finally the database is migrated by issuing the following command:</p>
<pre>grails migrate</pre>
<p>When everything goes fine your database has just been updated. If something goes wrong, you can either use the rollback commands provided or fall back to the backup of your database.</p>
<h2>Gotchas</h2>
<p>The following points present pitfalls you want to avoid (its enough that I hit them <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Please note that this is a living section, I keep adding new points I encounter.</p>
<h3>Use LiquiBase early!</h3>
<p>Make sure you start using LiquiBase early. Insert the DATABASECHANGELOG table as soon as possible and ensure that changesets are run against the databases.</p>
<h3>Backups, Backups, Backups...</h3>
<p>Backup your database before migrating! Really, do it!</p>
<h3>Stick to one Database Flavor</h3>
<p>Do not switch database flavors, e.g. from HSQLDB to MySQL. I tried this and I've encountered  a couple of issues with this. For example a changelog created from a HSQLDB may not run on a MySQL and vice versa due to different named datatypes (e.g. MySQL MEDIUMBLOB vs. HSQLDB VARBINARY). Further the changelog generated from a MySQL can cause problems on other databases as it names all primary keys "PRIMARY" per default. This leads to erroneous SQL that cannot be run.</p>
<p>Those problemes are nothing that couldn't be solved with a little bit of search and replace and even might be necessary to create the schema for a production database; but it is definitively nothing you want to do very often.</p>
<h3>How to Start Using LiquiBase in the Middle of a Project</h3>
<p>When you start to use LiquiBase in the middle of a project where there already is a database filled with precious production data, things can easily become complicated. The key to success here is to freeze the project or at least the part which affects the database schema for some time, generate a database changelog file from the current state and propagate this to all database instances. The reason why this is so important is that you need the DATABASECHANGELOG table on those databases; without this table and its entries  LiquiBase does not know which changes to apply. You could use the db-diff tool here, but the far more elegant approach is to simply propagate those changes to all databases once.</p>
<p>As soon as you have the DATABASECHANGELOG on all database instances, updating the schema becomes so easy that you will almost get addicted to it!</p>
<p>So, step by step:</p>
<ul>
<li>freeze your project for half an hour, maybe you can do this in the evening</li>
<li>create a new changelog file from the current schema with the <em>grails generate-changelog</em> command</li>
<li>mark all those changesets as imported with the <em>grails changelog-sync</em> command</li>
<li>push those changes to ALL databases associated with the project. If you fail to do so, migrating the schema of a database without those tables is almost impossible. Depending on the size of your database this requires a massive amount of time.</li>
<li>With the DATABASECHANGELOG table in place, migrating LiquiBase to the next version is as simple as entering grails migrate.</li>
</ul>
<h2>Conclusion</h2>
<p>LiquiBase is a great addition to Grails and you should really really think about using it. Otherwise managing changes to the database can easily become a big problem and im talking out of experience here. Hopefuly this post helps you to get started with LiquiBase. As always if you have any comments please feel to post.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/09/grails-and-liquibase-how-to-use/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>
