Xuff, px, bx, etc.
Created 28 November 2005, last updated 13 September 2021
As of September 2021, more of this page is out-of-date. The input files are still the same .bx and .px, but now they are served by Django. See Real Django site for details.
As of January 2008, half of this page is out-of-date. The input files are the same, but the process for turning them into HTML is completely different. See Permalinks, Gravatars, and Django for details.
I create this site with custom tools. They’ve grown organically over time. The end result is idiosyncratic, and I wouldn’t recommend them to anyone, but they work for me.
Briefly, my requirements were:
- All source must be in plain text files. This allows me the most flexibility to edit my pages, and change my mind later about how to process them.
- The site itself must be static HTML pages. When I started, I had no experience with LAMP or hosting providers, and I wanted as little infrastructure on the web host as possible.
- I had to be able to produce a staging version of the site on my own computer. This made it possible for me to fiddle with the site while not connected to the Internet.
I’ve used and grown these tools over the last four years. Things I like about them:
- I’ve been able to make incremental changes.
- They work.
Things I don’t like about them:
- XSLT can be an awkward way to produce HTML files, since it is declarative rather than procedural.
- I don’t get a chance to work with some cooler technologies.
- I can’t do truly dynamic rendering of content, for example, I have no way to produce a single blog entry per page.
My input files are all XML, in a handful of custom dialects. Pages start life as .px files; they look like this:
<?xml version='1.0' encoding='utf-8'?>
<page title='Xuff, px, bx, etc.'>
<p>I create this site with custom tools. They've grown organically over time.
The end result is idiosyncratic, and I wouldn't recommend them to anyone, but they
work for me.</p>
The dialect borrows liberally from XHTML, since that is a natural tagset to use when creating pages. For semantic constructs (such as the edit history of the page), I created my own tags. Each .px file eventually becomes a .html page on the site.
Blog entries are created in .bx files. Here’s a complete file:
<?xml version='1.0' encoding='utf-8'?>
<a href='http://www.layersmagazine.com/features/feature_cs2/flea.htm'>iPod Flea</a>.
The .bx files are converted into .px files in various ways to become pages on the site.
The conversion of files is done with XSLT transforms, run by a tool called Xuff. It’s an XML script engine. It knows how to perform tasks such as copying trees of files, collecting together a number of files into one XML file, running XSLT transforms over sets of files, splitting an XML file into a number of files, uploading files via FTP, and so on.
For example, here is a shortened snippet of all.xuff:
<files src='blog' include='*.bx' />
<xsl in='temp/all-blog.xml' style='blogmain.xslt' out='temp/blog/index.px' />
<xsl in='temp/all-blog.xml' style='feedentries.xslt' out='temp/blogfeed.xml' />
<xsl in='temp/blogfeed.xml' style='blogrss.xslt' out='html/blog/rss.xml'>
<param name='brief' value='y'/>
- creates a file all-blog.xml containing the contents of all the .bx files in the blog directory.
- transforms all-blog.xml with blogmain.xslt to produce blog/index.px
- transforms all-blog.xml with feedentries.xslt to produce blogfeed.xml
- transforms blogfeed.xml with blogrss.xslt to produce rss.xml, setting an XSLT parameter.
- transforms all of the .px files in the temp directory with subpage.xslt, producing .html files in the html directory as a result.
Whenever I change a file comprising my site, I run a Xuff file to create the entire site as HTML files and upload the changed files to my host. There’s no attempt to generate only part of the site. This isn’t fast (it takes about two minutes on my computer), but it is simple.
If you’d like to take a look at the tools or try them out, you can download a snapshot of a subset of my site. To use it:
- Install some prerequisite Python modules: PyXML, Pyana, and SilverCity.
- Unpack the snapshot (nedsite.zip) somewhere (let’s call it c:\nedsite)
- Edit try.xuff to set the base param:
<param name='base' value='file:///c:/nedsite/html/' />
- In the nedsite directory, execute:
This creates a local staging copy of the site.
python xuff.py try.xuff
- Launch a browser to c:\nedsite\html\index.html to see what you made.
If you use “python xuff.py tch.xuff” instead, it builds the files for the real site and uploads them to my host (except it won’t upload because it’s been neutered).
The snapshot zip file only includes a small subset of the blog entries (you’ll notice they all start with ‘a’), and some other large files are omitted, but the site should basically work.