<?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; Cool Tech</title>
	<atom:link href="http://www.jakusys.de/blog/category/cool-tech/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>Panorama Stitching with Hugin</title>
		<link>http://www.jakusys.de/blog/2009/05/panorama-stitching-with-hugin/</link>
		<comments>http://www.jakusys.de/blog/2009/05/panorama-stitching-with-hugin/#comments</comments>
		<pubDate>Sun, 24 May 2009 16:58:06 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Das tägliche Photo]]></category>
		<category><![CDATA[Toronto]]></category>
		<category><![CDATA[Hugin]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Panorama]]></category>
		<category><![CDATA[Photography]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=975</guid>
		<description><![CDATA[I recently moved into a new place and the view from the 38th floor is just amazing. So I came up with the idea of creating a nice panorama picture of it. After playing around with a few freeware and shareware solutions I stumbled accross Hugin, a open source panorama stitcher. I did my initial [...]]]></description>
			<content:encoded><![CDATA[<p>I recently moved into a new place and the view from the 38th floor is just amazing. So I came up with the idea of creating a nice panorama picture of it. After playing around with a few freeware and shareware solutions I stumbled accross <a title="Hugin Open Source Panorama Stitcher" href="http://hugin.sourceforge.net/" target="_blank">Hugin</a>, a open source panorama stitcher. I did my initial trial with pictures from my mobile phone and they turned out to be not really good. I re-took the images with my Canon Powershot in high res and spent some time to create a lot of control points and the result is amazing and very, very big. The original result file from Hugin was a 300 MB TIFF file. I scaled it down for the web, so enjoy the view over Toronto:</p>
<div id="attachment_977" class="wp-caption alignnone" style="width: 310px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2009/05/panorama_1_web.jpg" rel="lightbox[975]"><img class="size-medium wp-image-977" title="Panorama View over Toronto" src="http://www.jakusys.de/blog/wp-content/uploads/2009/05/panorama_1_web-300x61.jpg" alt="panorama_1_web" width="300" height="61" /></a><p class="wp-caption-text">Panorama View over Toronto</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2009/05/panorama-stitching-with-hugin/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Settlers 2, Pathfinding and Writing Code for Fun!</title>
		<link>http://www.jakusys.de/blog/2009/03/settlers-2-pathfinding-and-writing-code-for-fun/</link>
		<comments>http://www.jakusys.de/blog/2009/03/settlers-2-pathfinding-and-writing-code-for-fun/#comments</comments>
		<pubDate>Wed, 18 Mar 2009 02:59:35 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Settlers2]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=879</guid>
		<description><![CDATA[Last week or so I dug up something very amazing on The Piratebay. Someone packed up good old DOS classics into a Dosbox wrapper for Mac OS X, so I could start and run those games in a window on my Mac. Simply amazing. So I started up Settlers II, one of the best games [...]]]></description>
			<content:encoded><![CDATA[<p>Last week or so I dug up something very amazing on <a title="The Piratebay" href="http://en.wikipedia.org/wiki/The_Settlers_II" target="_blank">The Piratebay</a>. Someone packed up good old <a title="DOS" href="http://en.wikipedia.org/wiki/MS-DOS" target="_blank">DOS</a> classics into a <a title="DOSBox" href="http://www.dosbox.com/" target="_blank">Dosbox</a> wrapper for Mac OS X, so I could start and run those games in a window on my Mac. Simply amazing. So I started up <a title="Settlers II" href="http://en.wikipedia.org/wiki/The_Settlers_II" target="_blank">Settlers II</a>, one of the best games I've ever played. (Don't gimme any crap about pirating games! I own this game. And the expansion. What do you think have I been doing during my childhood? <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  )</p>
<p>So for all that don't know the game here's Settlers II in a nutshell: every player starts out with a headquarter, a limited amount of building materials, goods, tools, settlers with different skills and a small strip of land. The surroundings offer everything you need to build up your small empire: woods that can be cut down by lumberjacks, granite that can be cut by stone cutters, mountains that offer coal, ore and gold and flat land that can be used to grow crops. On of the major challenges of this game is to get all the production chains right: let's take for example a lumberjack. A lumberjack cuts down trees. The logs then needs to be transported to a sawmill where they get cut into handy boards. (Picture 1 shows such a production chain.) These boards in turn then need to get to a stock or to construction sites. And if you don't build a forester your lumberjack will run out of trees very soon. That was one of the easier production chains. Let's look at something more sophisticated: production of meat. You'll start of with a farm that grows crops. Then you need a pigfarm that takes the crops grown by the farm and water from a well to breed pigs. And finally, to get to your tasty meat, you'll need a slaughterhouse. So, all in all, getting those production chains right tricky and very rewarding. Nothing better than seeing wares running smoothly form source to destination (at least for me <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  ).</p>
<div id="attachment_883" class="wp-caption alignnone" style="width: 412px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-23.png" rel="lightbox[879]"><img class="size-full wp-image-883" title="Picture 1: Production chain for lumber" src="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-23.png" alt="Picture 1: Production chain for lumber" width="402" height="283" /></a><p class="wp-caption-text">Picture 1: A production chain for lumber. On the bottom left there is the forrester. The guy living in that building just keeps planting trees. The building at the top left and to the right are lumberjacks.They cut down trees. Those trees then get transported to the building to the top right, the sawmill where they get cut up.</p></div>
<p>The other big challenge, and actually the reason why I'm blogging about this, is the way system. All the production facilities mentioned above are connected by a road system. Each of those buildings has a flag in front it and whenever a building "finishes" producing an item, the item gets dropped at the flag (I won't go into the hygienically implications of dropping food on flag on a dusty road... ). Connected to the flag is a road that leads to another flag and standing on that road is a carrier, a poor guy who's job it is to just carry stuff from the one flag to the other flag. See Picture 2 to get a better understanding. So eventually this road leads to another building that actually needs what has been produced. In the picture below that would be the small pig on the flag to the right that needs to get to the slaughterhouse to the left (Hey, it's biological after all!).</p>
<div id="attachment_880" class="wp-caption alignnone" style="width: 327px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-22.png" rel="lightbox[879]"><img class="size-full wp-image-880" title="Picture 1: Flags, roads and items. " src="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-22.png" alt="Flags, roads and items. " width="317" height="141" /></a><p class="wp-caption-text">Picture 2: Flags, roads and items. Notice the pig on the flag on the right. </p></div>
<p>So getting the way system right is crucial to your success in that game. If your roads are too long, it will take forever to complete things. If you don't set enough flags, the actual capacity of a given road segment will drop - after all there is only one guy standing between two flags and he can carry only one item at once (an exception are the donkeys that you get after a road has been in heavy use but that still only gives you two items per segment).</p>
<p>Now, you have an understanding of what that game is about. If you don't, get yourself a copy and play it a bit. But be careful, it's addictive.</p>
<p>So while I was playing a bit I started to wonder, how all this worked. How do wares get routed from one flag to another flag. How to flags eventually reach their destination? How is ensured that wares don't run in circles? How is ensured that best possible route is taken? All those thoughts kind of reminded me of my excellent <a title="Algorithmen und Datenstrukturen I" href="https://sol.cs.hm.edu/fi/rest/public/modul/title/algorithmenunddatenstruktureni" target="_blank">algorithms and data</a> <a title="Algorithmen und Datenstrukturen II" href="https://sol.cs.hm.edu/fi/rest/public/modul/title/algorithmenunddatenstrukturenii" target="_blank">structures lessons</a> at the <a title="Hochschule München" href="http://www.hm.edu/" target="_blank">Hochschule München</a>, where graphs and different algorithms on graphs where a big subject. So I got really curious how to implement something like that. After all, at university we implemented a lot of the data structures and algorithms but never for a "real" problem.</p>
<p>Later that night I started up Eclipse and got churned out some code to actually represent a hexgonal map (Settlers 2 uses a hexagonal grid as opposed to most modern games that just use isometric rectangular maps), render out that map to the screen and some classes to represent flags and roads. And then the fun started...</p>
<p>My first goal was to implement a pathfinding algorithm that actually finds a good route from one given hexagon to another hexagon. Sounds easy but is a really hard problem. There are a couple of algorithms out there that actually solve that problem but I decided to go with the simplest one, <a title="Dijsktras Algorithm" href="http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm" target="_blank">Dijsktras algorithm</a> that is guaranteed to produce the best solution. However implementing that algorithm wasn't as easy as I anticipated. My first test run produced some rather... unexpected results:</p>
<div id="attachment_887" class="wp-caption alignnone" style="width: 754px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-17.png" rel="lightbox[879]"><img class="size-full wp-image-887" title="Picture 3: Pathfinding done wrong!" src="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-17.png" alt="Picture 3: Pathfinding done wrong!" width="744" height="739" /></a><p class="wp-caption-text">Picture 3: Pathfinding done wrong. The goal was to find the shortest possible route from the one green flag to the other green flag... The gray zig-zag line is the path my implementation found...</p></div>
<p>Obviously that was not the best possible solution! Eventually it took me a couple of hours to get my implementation right. But then I got it right:</p>
<div id="attachment_890" class="wp-caption alignnone" style="width: 749px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-18.png" rel="lightbox[879]"><img class="size-full wp-image-890" title="Picture 4: Pathfinding done right!" src="http://www.jakusys.de/blog/wp-content/uploads/2009/03/picture-18.png" alt="Picture 4: Pathfinding done right!" width="739" height="743" /></a><p class="wp-caption-text">Picture 4: Pathfinding done right! Made the paths red in that screenshot for better visibility. Note how the red paths connecting the green flags are the shortest possible. </p></div>
<p>My conclusion after a couple of hours trying to get that right: It was a lot of fun and kudos to the developers of Settlers 2! I did not spend too much time on that but it became quickly obvious that building a game as "simple" as this old DOS game is all but easy. Building even simple pathfinding imposed quite a challenge on me. Building a whole game like that seems one hell of a task...</p>
<p>The next step is now to build a pathfinder that is actually aware of terrain (you can't build roads on water!) and won't allow to cross roads. With that in place i can finally start to play around with the actual routing of goods in this graph. The technical more adept might argue that I actually don't need all the stuff that I wrote so far to calculate some spanning trees on a graph. And they're right. But otherwise it wouldn't be as much fun!</p>
<p>Depending on how much spare time I have I'll keep playing around with this and keep you posted...</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2009/03/settlers-2-pathfinding-and-writing-code-for-fun/feed/</wfw:commentRss>
		<slash:comments>13</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>Songbird &#8211; an iTunes Alternative</title>
		<link>http://www.jakusys.de/blog/2008/11/songbird-an-itunes-alternative/</link>
		<comments>http://www.jakusys.de/blog/2008/11/songbird-an-itunes-alternative/#comments</comments>
		<pubDate>Fri, 07 Nov 2008 01:57:21 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=520</guid>
		<description><![CDATA[For all who are far from satisfied with iTunes: you should check out Songbird, an open media source player open source media player. It's great. It can play all those formats iTunes cannot play (which basically is only MP3).
Songbird features a real plugin system, it's skinnable and has lot's of neat features! Go for it!
]]></description>
			<content:encoded><![CDATA[<p>For all who are far from satisfied with iTunes: you should check out <a title="Songbird" href="http://getsongbird.com/" target="_blank">Songbird</a>, an <span style="text-decoration: line-through;">open media source player</span> open source media player. It's great. It can play all those formats iTunes cannot play (which basically is only MP3).</p>
<p>Songbird features a real plugin system, it's skinnable and has lot's of neat features! Go for it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/11/songbird-an-itunes-alternative/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Good old Games</title>
		<link>http://www.jakusys.de/blog/2008/09/good-old-games/</link>
		<comments>http://www.jakusys.de/blog/2008/09/good-old-games/#comments</comments>
		<pubDate>Fri, 26 Sep 2008 17:25:01 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=375</guid>
		<description><![CDATA[Just stumbled accross Good old Games, they are planning to re-release old classic games. I'm really excited about this! I love old games, but getting them to run on recent hardware is a pain. And the best part: without any crappy DRM! Hope they start business soon.  
]]></description>
			<content:encoded><![CDATA[<p>Just stumbled accross <a title="Good Old Games" href="http://www.gog.com/" target="_blank">Good old Games</a>, they are planning to re-release old classic games. I'm really excited about this! I love old games, but getting them to run on recent hardware is a pain. And the best part: without any crappy DRM! Hope they start business soon. <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/09/good-old-games/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>
		<item>
		<title>Virtuelles, genopptes Plastik</title>
		<link>http://www.jakusys.de/blog/2008/07/virtuelles-genopptes-plastik/</link>
		<comments>http://www.jakusys.de/blog/2008/07/virtuelles-genopptes-plastik/#comments</comments>
		<pubDate>Mon, 21 Jul 2008 18:20:51 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Das tägliche Photo]]></category>
		<category><![CDATA[Lego]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=26</guid>
		<description><![CDATA[Gestern Abend habe ich eine großartige Software gefunden, den Lego Digital Creator (LDD), den man kostenlos herunterladen kann. Der LDD ist eine virtuelle Lego-Box mit sehr sehr vielen unterschiedlichen Teilen (obwohl ich doch schon einige nicht finden konnte, z.B. Differentialgetriebe oder diese Schutzblechdingens die alles in allem 5 oder 6 Noppen lang waren und die [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_27" class="wp-caption alignleft" style="width: 160px"><a href="http://www.jakusys.de/blog/wp-content/uploads/2008/07/lddscreenshot1.png" rel="lightbox[26]"><img class="size-thumbnail wp-image-27" title="LEGO" src="http://www.jakusys.de/blog/wp-content/uploads/2008/07/lddscreenshot1-150x150.png" alt="LEGO" width="150" height="150" /></a><p class="wp-caption-text">LEGO</p></div>
<p>Gestern Abend habe ich eine großartige Software gefunden, den <a title="Lego Digital Creator" href="http://ldd.lego.com" target="_blank">Lego Digital Creator</a> (LDD), den man kostenlos herunterladen kann. Der LDD ist eine virtuelle Lego-Box mit sehr sehr vielen unterschiedlichen Teilen (obwohl ich doch schon einige nicht finden konnte, z.B. Differentialgetriebe oder diese Schutzblechdingens die alles in allem 5 oder 6 Noppen lang waren und die Radladerschaufeln sowieso... ) und einem unerschöpflichen Vorrat an Steinen in alle Farben -- ich hab schon versucht sie alle mal aufzubrauchen, aber es sind einfach nicht weniger geworden <img src='http://www.jakusys.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> . Der LDD kommt mit einer schicken 3D-Oberfläche daher, die Steuerung ist intuitiv und bietet neben dem eigentlichen Bauspaß mit der Explosionsanimation, bei der das eben Erbaute in alle Einzelteile explodiert und sich dann wieder zusammenfügt, auch Befriedigung für die eher destruktiv veranlagten. Und ja, es gibt eine Mac-Version! Danke Lego!</p>
<p>Wenn man mit dem was man erschaffen hat zufrieden ist, kann man sogar sein Modell bei Lego bestellen; bei fast allen Modellen die ich bis jetzt gebaut habe, wurde ich dann aber darauf hingewiesen das bestimmte Steine nicht bestellt werden können, und somit mein Modell nicht bestellbar ist. Aber das ist ja nicht so tragisch -- das zusammenbauen alleine macht schon so viel Spaß!</p>
<p>Darüber hinaus gibts hier noch das heutige Bild! 
<a href='http://www.jakusys.de/blog/2008/07/virtuelles-genopptes-plastik/lddscreenshot1/' title='LEGO'><img width="150" height="150" src="http://www.jakusys.de/blog/wp-content/uploads/2008/07/lddscreenshot1-150x150.png" class="attachment-thumbnail" alt="LEGO" title="LEGO" /></a>
<a href='http://www.jakusys.de/blog/2008/07/virtuelles-genopptes-plastik/photo-11/' title='2008-07-21'><img width="150" height="150" src="http://www.jakusys.de/blog/wp-content/uploads/2008/07/photo-11-150x150.jpg" class="attachment-thumbnail" alt="2008-07-21" title="2008-07-21" /></a>
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/07/virtuelles-genopptes-plastik/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Der Nahkampfregenschirm</title>
		<link>http://www.jakusys.de/blog/2008/07/der-nahkampfregenschirm/</link>
		<comments>http://www.jakusys.de/blog/2008/07/der-nahkampfregenschirm/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 22:07:54 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>
		<category><![CDATA[Martial Arts]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=14</guid>
		<description><![CDATA[Einfach irre, ich will auch so einen unkaputtbaren Nahkampfregenschirm: http://blog.wired.com/gadgets/2008/07/unbreakable-fig.html
]]></description>
			<content:encoded><![CDATA[<p>Einfach irre, ich will auch so einen unkaputtbaren Nahkampfregenschirm: <a href="http://blog.wired.com/gadgets/2008/07/unbreakable-fig.html" target="_blank">http://blog.wired.com/gadgets/2008/07/unbreakable-fig.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/07/der-nahkampfregenschirm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reactable</title>
		<link>http://www.jakusys.de/blog/2008/07/reactable/</link>
		<comments>http://www.jakusys.de/blog/2008/07/reactable/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 10:12:23 +0000</pubDate>
		<dc:creator>Jakob Külzer</dc:creator>
				<category><![CDATA[Cool Tech]]></category>

		<guid isPermaLink="false">http://www.jakusys.de/blog/?p=12</guid>
		<description><![CDATA[
Den Reactable habe ich das erste mal in einem kurzen Bericht im Fernsehen gesehen und war sofort fasziniert; ein Tisch mit einer reaktiven Oberfläche der bei Auflegen von "Bausteinen" Geräusche erzeugt. Die Videopräsentationen muss man sich einfach ansehen: Basic Demo #1, Live in Berlin. Das ist so cool!
Interessanterweise stellen die Macher des Reactable ihr Framework [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jakusys.de/blog/wp-content/uploads/2008/07/reactable.jpg" rel="lightbox[12]"><img class="alignleft size-thumbnail wp-image-13" title="Reactable in Aktion" src="http://www.jakusys.de/blog/wp-content/uploads/2008/07/reactable-150x150.jpg" alt="Reactable in Aktion" width="150" height="150" /></a></p>
<p>Den <a title="Reactable Homepage" href="http://reactable.iua.upf.edu/" target="_blank">Reactable</a> habe ich das erste mal in einem kurzen Bericht im Fernsehen gesehen und war sofort fasziniert; ein Tisch mit einer reaktiven Oberfläche der bei Auflegen von "Bausteinen" Geräusche erzeugt. Die Videopräsentationen muss man sich einfach ansehen: <a title="Reactable Basic Demo" href="http://www.youtube.com/watch?v=0h-RhyopUmc" target="_blank">Basic Demo #1</a>, <a title="Reactable live in Berlin at YouTube" href="http://www.youtube.com/watch?v=vm_FzLya8y4&amp;feature=related" target="_blank">Live in Berlin</a>. Das ist so cool!</p>
<p>Interessanterweise stellen die Macher des Reactable ihr Framework für die "Benutzeroberfläche" zur Verfügung. Damit ließen sich wirklich tolle Sachen machen, man stelle sich einfach die Möglichkeiten eines absolut intuitiven und Hilfsmittelfreien Systems vor! Wo bekomme ich jetzt so einen Tisch her?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jakusys.de/blog/2008/07/reactable/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
