Which seems on the face of it to be pretty cool although all those extra elements don't really help with the readability of the actual file I was thinking about a xml comment driven system using NaturalDoc or similar.
An interesting idea, I think I tend to agree with you about the potential for making the XSL even less readable!
Currently I just use standard XML comments within my Umbraco XSL files although I have not tried to generate external documentation files from these comments. I guess it depends on the size and complexity of your XSL files. I would be interested to hear how you eventually solve this.
I've always used XML comments (I don't only use XSLT in Umbraco), and then I just collapse them in the editor (I use TextMate but many editors/IDEs support folding) if they're too lengthy.
Though not quite the same idea (depends on how you want to document them) you could take a look at XSpec, which is a way to develop XSLT using a BDD-style framework, where you document the behavior of the various templates/functions before you actually code them.
I agree, looks promising. I like the fact the documentation can then be used as unit tests for the XSLT you write, I can imagine an extension for Umbraco that would allow these tests to be run from within the UI, either after each save or from a seperate Test Run button.
( although personally I now do all my XSLT development within Visual Studio, so being able to run the tests within VS would be useful. )
Do keep us updated how you get on with this Peter!
Will do Chris, I'm cursed with having too many ideas and toys and not enough time at the minute, oh what I'd give for a week of geeking it up with some beer!
I've found XSLDoc (different to XSLTDoc) too which uses XML comments to document your files. Takes some of the noise away as we mentioned but you loose some of the extras that XSLTDoc gives you.
Ok, another update, this might be a long one. XSpec, heres an actual example and a how to.
Installation:
Download XSpec (http://code.google.com/p/xspec/downloads/list) and unzip somewhere handy
Ensure you've got Java installed (your on your own on that one, bit beyond the scope)
Download Saxon 9 (http://sourceforge.net/projects/saxon/files/Saxon-HE/9.2/saxonhe9-2-0-3j.zip/download) and unzip somewhere handy
Open the xspec.bat file from your XSpec folder that you unzipped and change line 3 to point to the .jar file which is in your Saxon folder (eg SET CP=C:\Program Files\Java\Saxon\saxon9he.jar)
Open a command prompt and switch directory to your xspec directory
Cut and paste the two files listed below (_image.xsl and test_image.xsl) into your XSpec folder
Run "xspec test_thumbnail.xsl"
Job done, this "should" open the results in your browser. Woohoo, welcome to Behaviour Driven Development for XSL!
Right could of example files to come, first off the original XSL file from one of my Umbraco Macros.This is used to create a thumbnail of any image (using my own .net thumbnailer) pretty simple:
Straight away its obvious that this is not really that re-usable or that easy to test. I like to have any handy functions in include files so they are easy to re-use not just between projects but also between macros. So I wanted to move this template around a little, here what I did:
I created a new include XSL file called "_Images.xsl" but did not create a matching marco for it. Notice the leading underscore, I've started using this for marking none macro XSL files, it makes them stand out from the others.
I modified my existing "RenderImage" XSL file to include my new child XSL file
I then cut the bulk of the code out into a original file and moved it to a new template called "Image.RenderByMediaID", this has several params on it which match the variables in the original, they are all optional except MediaID.
At this point I spotted that I might want to render a thumbnail from other macros that are not using a media content item, so I created another template called "Image.RenderByUrl" which again excepts all the same params, except it takes a url rather than a media id.
"Image.RenderByMediaID" was then changed to use "Image.RenderByUrl" under the hood and pass the url of the media item to the template. Lots of chaining of templates and passing a params. It looks a bit clumsy but its actually really reusable and simple I think
Notice all the variables have gone, we now just get the values for those direct in the template. By removing the variables from global scope we can also use some sensible variables and param names in the rest of our code. Notice that we use alot of the same variable names, we don't do any of the old "mediaID2", "thisMediaID", "myMediaID" stuff, that just leads to confusion I think, instead we use XSL's built in scoping and stick to it, once we've made that choice we have to stick to it but it makes it easier in the long run, honest :)
Right, now thats a bit more easy to test. Why? Well I now only really have to test "Image.RenderByUrl" as thats the one thats doing the output. Thats the one that I want to ensure is doing what it should. Everything else just passes params into this template so this is the place to start.
So for those following along at home (and to make it easy for you) here is a blank XSpec test file (you lucky people I could not find one of these so had to build it together through trial and error:
<!--
Things you need to do: * Read http://code.google.com/p/xspec/wiki/WritingScenarios * Change stylesheet in the x:description element to the relative name of the XSL file you want to test * Add x:scenario elements for each test you want to do * The x:expect element can contain your expected XML/HTML output
XSpec can do alot more but this will do, seriously go read that link above
<x:scenario label="When I do this"> <x:call template="You xsl template name here"> <x:param name="your_param" select="'your value'" /> </x:call> <x:expect label="it should return this"> <p>my XML output here</p> </x:expect> </x:scenario>
</x:description>
So time for some tests! Heres the first one, given a url will it render out a img tag with the right url? I created this file and saved it as "test_thumbnail.xsl"
<x:description xslt-version="1.0" xmlns:x="http://www.jenitennison.com/xslt/xspec" stylesheet="thumbnail.xsl"> <x:scenario label="When called with just a URL"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src and blank alt"> <img src="/umbraco/thumbnail.aspx?image=test.jpg" alt="" /> </x:expect> </x:scenario> </x:description>
One gotcha, just like XSL (as it is XSL) I noticed that I had to wrap my test string in single quotes, school boy error but still worth pointing out.
To run this I simply type "xspec test_thumbnail.xsl" in my command prompt (remember you have to be in the folder you unzipped the xspec into for this to work or put the xspec bat file in your PATH environment variable).
Ok that one test worked a treat, the result opened in my browser all tested and passed. I need more tests, as I have lot of params in this one:
<x:scenario label="When called with just a URL"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src and blank alt"> <img src="/umbraco/thumbnail.aspx?image=test.jpg" alt="" /> </x:expect> </x:scenario>
<x:scenario label="When called with a URL and alt"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> <x:param name="alt" select="'testing, testing'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src with alt text"> <img src="/umbraco/thumbnail.aspx?image=test.jpg" alt="testing, testing" /> </x:expect> </x:scenario>
<x:scenario label="When called with URL and height"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> <x:param name="height" select="'100'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src with height query string param"> <img src="/umbraco/thumbnail.aspx?image=test.jpg&height=100" alt="" /> </x:expect> </x:scenario>
<x:scenario label="When called with URL and width"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> <x:param name="width" select="'200'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src with width query string param"> <img src="/umbraco/thumbnail.aspx?image=test.jpg&width=200" alt="" /> </x:expect> </x:scenario>
<x:scenario label="When called with URL, width and height"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> <x:param name="width" select="'200'" /> <x:param name="height" select="'100'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src with height and width query string param"> <img src="/umbraco/thumbnail.aspx?image=test.jpg&width=200&height=100" alt="" /> </x:expect> </x:scenario>
<x:scenario label="When called with URL and css class"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> <x:param name="class" select="'test_class'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src and the css class attribute included"> <img src="/umbraco/thumbnail.aspx?image=test.jpg" alt="" class="test_class" /> </x:expect> </x:scenario>
<x:scenario label="When called with URL and id"> <x:call template="Image.RenderByUrl"> <x:param name="url" select="'test.jpg'" /> <x:param name="id" select="'my_id'" /> </x:call> <x:expect label="it should return an image tag with correct thumbnailer src and the DOM id attribute included"> <img src="/umbraco/thumbnail.aspx?image=test.jpg" alt="" id="my_id" /> </x:expect> </x:scenario>
An running this lot I found an error! I never render out the alt attribute! I might not have spotted that without my tests, so I added to my Image.RenderByUrl template:
So how did that feel? Well a bit long winded if honest as it was an up hill slog to get it all setup and running. But now I've been through the pain (and documented it here so you don't have to) I really liked it. Forced me to re-think my code and I'm looking forward to creating more test for more of my XSL (not just Umbraco but others too). I quite like it and with some cut and pasting creating the additional test for my image template was actually pretty swift.
Whats next, more testing and I need away of getting this wired up into my Cruise Control build server. Also there is a doc about how to get xspec working in Oxygen XML editor, it should be possible to wire it up to Visual Studio and maybe Umbraco itself? Bit out my hands those last bits though :)
Great writeup! I've found XSpec very good for refactoring (as you just showed here) and for times when someone needs "this XML format transformed to that format" - because you can chuck along one test at a time, until you reach "all green".
I've had a few gotchas with the currentPage parameter that I'm hoping to document here (or in the wiki) when time permits...
Thanks again for taking the time to write this up.
That was a great post, thanks for the very comprehensive update!
I, like you, have too many things on, and not enough time to play with the toys or do the fun coding I'd like to do, some how paid for work always seems to have to take priority, roll on 2010 for a few changes of priorities :)
It would be nice to port this to run using .NET and the MS XSLT parser rather than Saxon, then from an Umbraco point of view we can be sure it's definitely going to work within Umbraco and we don't get tempted to add XSLT 2 code that will fail if you try and run it within Umbraco.
This would also reduce the number of dependancy's and probably make it easier to integrate with VS and maybe within Umbraco?!
Now there's a challenge for the Christmas hols ;-)
Next step is to document my two new templates using both of the documenting tools (XSLDoc and XSLTDoc) and see which one I like the most. I'll post details of that up here too. Might convert these posts into Books as well.
Finally, I'll try to read through my posts more before I post (TopGear was on so was in a rush!)
Did some quick digging into why it uses Saxon. It uses alot of XSL2 code to generate all the tests and Saxon (correct me if wrong) is the only parser that will handle XSL2 with there being nothing similar natively in .net
The good news is there is a .net version of Saxon which you could include to remove the need for the Java maybe?
Having XSL2 in Umbraco could be fun though :)
You can set which version of XSL you are using in the <x:description /> element (I set it to version 1 in my demos above as it defaults to version 2) this stops it allowing you to use anything from XSL2 in your templates, so should be safe?
Documenting XSLT, any ideas?
We've got another XSL project with alot of XSL files which I'm hoping to document but not sure how. Quick google around found this:
http://www.pnp-software.com/XSLTdoc/index.html#DocumentingTheCode
Which seems on the face of it to be pretty cool although all those extra elements don't really help with the readability of the actual file I was thinking about a xml comment driven system using NaturalDoc or similar.
Anyone got any ideas/tips?
Hi Peter,
An interesting idea, I think I tend to agree with you about the potential for making the XSL even less readable!
Currently I just use standard XML comments within my Umbraco XSL files although I have not tried to generate external documentation files from these comments. I guess it depends on the size and complexity of your XSL files. I would be interested to hear how you eventually solve this.
Cheers,
Chris
I've always used XML comments (I don't only use XSLT in Umbraco), and then I just collapse them in the editor (I use TextMate but many editors/IDEs support folding) if they're too lengthy.
Though not quite the same idea (depends on how you want to document them) you could take a look at XSpec, which is a way to develop XSLT using a BDD-style framework, where you document the behavior of the various templates/functions before you actually code them.
/Chriztian
Xspec is a great find! Thank you Chriztian, will have a more indepth read up on that one later and a bit of a play too.
I agree, looks promising. I like the fact the documentation can then be used as unit tests for the XSLT you write, I can imagine an extension for Umbraco that would allow these tests to be run from within the UI, either after each save or from a seperate Test Run button.
( although personally I now do all my XSLT development within Visual Studio, so being able to run the tests within VS would be useful. )
Do keep us updated how you get on with this Peter!
Cheers,
Chris
Will do Chris, I'm cursed with having too many ideas and toys and not enough time at the minute, oh what I'd give for a week of geeking it up with some beer!
I've found XSLDoc (different to XSLTDoc) too which uses XML comments to document your files. Takes some of the noise away as we mentioned but you loose some of the extras that XSLTDoc gives you.
http://www.bacman.net/apps/XSLdoc/
One nice feature is that you can generate Docs on the fly via a website: http://www.bacman.net/apps/XSLdoc/XSLdoc.jsp?URL=http://www.bacman.net/apps/XSLdoc/xsl/test.xsl
Can't say I'm overly impressed with the output though, not exactly easy to read :(
More to follow...
Ok, another update, this might be a long one. XSpec, heres an actual example and a how to.
Installation:
Job done, this "should" open the results in your browser. Woohoo, welcome to Behaviour Driven Development for XSL!
Right could of example files to come, first off the original XSL file from one of my Umbraco Macros.This is used to create a thumbnail of any image (using my own .net thumbnailer) pretty simple:
Straight away its obvious that this is not really that re-usable or that easy to test. I like to have any handy functions in include files so they are easy to re-use not just between projects but also between macros. So I wanted to move this template around a little, here what I did:
Ok heres the code after the refactoring:
Our new "_Image.xsl" include file:
Save this one as "_image.xsl"
And the new RenderImage.xsl file:
Notice all the variables have gone, we now just get the values for those direct in the template. By removing the variables from global scope we can also use some sensible variables and param names in the rest of our code. Notice that we use alot of the same variable names, we don't do any of the old "mediaID2", "thisMediaID", "myMediaID" stuff, that just leads to confusion I think, instead we use XSL's built in scoping and stick to it, once we've made that choice we have to stick to it but it makes it easier in the long run, honest :)
Right, now thats a bit more easy to test. Why? Well I now only really have to test "Image.RenderByUrl" as thats the one thats doing the output. Thats the one that I want to ensure is doing what it should. Everything else just passes params into this template so this is the place to start.
So for those following along at home (and to make it easy for you) here is a blank XSpec test file (you lucky people I could not find one of these so had to build it together through trial and error:
So time for some tests! Heres the first one, given a url will it render out a img tag with the right url? I created this file and saved it as "test_thumbnail.xsl"
One gotcha, just like XSL (as it is XSL) I noticed that I had to wrap my test string in single quotes, school boy error but still worth pointing out.
To run this I simply type "xspec test_thumbnail.xsl" in my command prompt (remember you have to be in the folder you unzipped the xspec into for this to work or put the xspec bat file in your PATH environment variable).
Ok that one test worked a treat, the result opened in my browser all tested and passed. I need more tests, as I have lot of params in this one:
Save this one as "test_image.xsl"
An running this lot I found an error! I never render out the alt attribute! I might not have spotted that without my tests, so I added to my Image.RenderByUrl template:
So how did that feel? Well a bit long winded if honest as it was an up hill slog to get it all setup and running. But now I've been through the pain (and documented it here so you don't have to) I really liked it. Forced me to re-think my code and I'm looking forward to creating more test for more of my XSL (not just Umbraco but others too). I quite like it and with some cut and pasting creating the additional test for my image template was actually pretty swift.
Whats next, more testing and I need away of getting this wired up into my Cruise Control build server. Also there is a doc about how to get xspec working in Oxygen XML editor, it should be possible to wire it up to Visual Studio and maybe Umbraco itself? Bit out my hands those last bits though :)
Hope that helps and sorry for the length
Pete
Hi Peter,
Great writeup! I've found XSpec very good for refactoring (as you just showed here) and for times when someone needs "this XML format transformed to that format" - because you can chuck along one test at a time, until you reach "all green".
I've had a few gotchas with the currentPage parameter that I'm hoping to document here (or in the wiki) when time permits...
Thanks again for taking the time to write this up.
/Chriztian
Hi Pete,
That was a great post, thanks for the very comprehensive update!
I, like you, have too many things on, and not enough time to play with the toys or do the fun coding I'd like to do, some how paid for work always seems to have to take priority, roll on 2010 for a few changes of priorities :)
It would be nice to port this to run using .NET and the MS XSLT parser rather than Saxon, then from an Umbraco point of view we can be sure it's definitely going to work within Umbraco and we don't get tempted to add XSLT 2 code that will fail if you try and run it within Umbraco.
This would also reduce the number of dependancy's and probably make it easier to integrate with VS and maybe within Umbraco?!
Now there's a challenge for the Christmas hols ;-)
Cheers,
Chris
Are you taking that challenge on then Chris? :)
Next step is to document my two new templates using both of the documenting tools (XSLDoc and XSLTDoc) and see which one I like the most. I'll post details of that up here too. Might convert these posts into Books as well.
Finally, I'll try to read through my posts more before I post (TopGear was on so was in a rush!)
Cheers
Pete
Did some quick digging into why it uses Saxon. It uses alot of XSL2 code to generate all the tests and Saxon (correct me if wrong) is the only parser that will handle XSL2 with there being nothing similar natively in .net
The good news is there is a .net version of Saxon which you could include to remove the need for the Java maybe?
Having XSL2 in Umbraco could be fun though :)
You can set which version of XSL you are using in the <x:description /> element (I set it to version 1 in my demos above as it defaults to version 2) this stops it allowing you to use anything from XSL2 in your templates, so should be safe?
Hope that helps
Pete
is working on a reply...