This explains how this site and blog are built around XML/XSLT, python, and httpd.
This is here in case any peers or potential employers are interested in how I create "microservice" websites if I have full control over architecture.
I like this architecture because it allows me to reuse stylable components like the section contents menu that you see on the left. Adding this functionality to a page is just a matter of enclosing my text and markup in a custom <section> tag and embedding a placeholder <sectioncontents> tag somewhere on the page. The table and all the section numbering is generated by an XSLT template.
Essentially, each human-authored document passes through a rendering pipeline. Different stages of the pipeline perform XSLT pattern replacement on the output of a previous stage. These stages occur during development, but could be run later during production, and even right at page request time.
A simple static page with widgets can be built using just one of these stages. Only the most complicated cases require all three stages.
Each stage is performed by XSLT (provided by libxslt). This handy library can take an .xml document and apply search-and-replace pattern substitution rules on the markup to produce a result document for the next stage of the pipeline. This allows you to define "widgets" in the form of custom tags and markup that can be reused across authored pages.
The placement of a widget in a page can be as simple as enclosing your markup in a custom tag, but this can result in the inclusion of numerous style sheets and a complex enclosing structure or other things like links and anchors to your content from different parts of the page.
The three phases of the rendering pipeline are named pre-rendering, production, and presentation.
Here's a diagram showing the workflow with tabs at the bottom to navigate the different stages:
Not every page requires the entire pipeline.
Most static web pages can be implemented as a single .xhtml file.
This file can be pure HTML and can use widgets by embedding custom tags that are defined in .xsl files.
A simple static page only requires a single xhtml file. This gets processed by build scripts and placed in Apache's htdocs/
If you want to create reusable widgets, you put all their markup (and even inline CSS) into separate .xsl files that explain how to pattern-match your custom tags and emit markup into a result document.
The sources of this page live under a source directory, while the outputs of this stage are placed under a build directory that can be immediately served by the web server (htdocs/).
The .xhtml files may require subsequent in-place modification due to external events.
For example, a bidirectional link may break, an auction timer may expire, or a weather prediction may need updating.
Background processes on the web server can respond to these events and run subsequent .xsl transforms on the production documents.
Some of the page data may be entirely dependent on the user or their current browse session.
At request time, an apache module can run late XSLT transforms on the production documents to embed this data into the document. The result of these transforms is a customized in-memory version of the document that is served to the user.
This can alleviate the need for AJAX callbacks that would otherwise slow page loading -- an important detail for microservices.
The custom tags you create in your widget.xsl files can represent fairly complex layout structures and also intermix the usual HTML and CSS. Your human-authored documents are thus quite easy to manage in a standard text editor. These structural style elements can then be configured in .XSL and applied to the entire site via the rendering pipeline.
The only rendering pass required by this website and blog occurs when I run my Makefile to convert my authored .xml content into .xhtml document views.
The source for a blog entry can be quite simple. Let's take a look at a simple use of the prerendering phase to take the <title> element that is normally found in the <head> element of an .html file and emit this as a text heading in the body of the html itself. Consider the two files:
This is what I did today. Blah, blah, blah ...
<xs:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" version="1.0"> <xsl:template match="/html/body//title-heading"> <h2> <xsl:value-of select="/html/head/title"/> </h2> </xsl:template> ... (other templates omitted for brevity) ... </xs:stylesheet>
So far, this looks like a typical XSLT "hello, world" example. In our case though, it's worth noting that the only kind of element replacements that can go into prerender.xsl are only the kind for which the replacement data (here the <h2> tags) are known prior to live deployment to an http server. Any custom tags that depend on data that isn't available at this stage will need to be put in separate .xsl file and deployed to the server to be run in a later rendering stage.
If the interpreter embedded in the server performs these transformations (as with PHP), it increases load on the server and increases page latency while the transformation is occuring. So by prerendering as much content as we can, we gain an immediate speed-up by applying prerender.xsl as part of an offline development workflow. Any data that was known at authoring time is rendered immediately rather than repeating the same operations for each client request.
In other web development frameworks, this kind of prerendering stage requires explicit scripting and customization to engineer, or the inclusion of server plugins. We can accomplish this with just the two files you see above and a handy command line tool called xsltproc, which is available in most Linux distributions via libxslt. In addition, we'll use the same exact XSL syntax when designing the rendering phases for production and presentation.
The output is an index.xhtml file that can be served to browsers right away. I usually keep this in a builds/ directory that is separate from my source files. It's this directory that is deployed to the server and published.
And that's what you are currently reading.