Cindy is a template engine that was designed to solve the problem of application developers modifying web designer HTML. There have been earlier approaches who did this well. The earliest one I know about is HTML Tree. Another one is Zope's TAL. There are at least two recent engines working on completely unmodified HTML. These are Template::Semantic and PURE. The term unobtrusive (as used by PURE) for template engines that work on valid HTML without any special content describes this approach best.
Cindy does however go further. It is not a library that mangles data provided through an API. To achieve complete decoupling of application and design the application delivers its data as XML (or parse able HTML). Cindy then moves these data into templates. As a consequence Cindy is language independent.
This resembles a limited version of XSL. The big difference is that Cindy is still a template engine, that is dreamweaver compatible. XSL mixes output template and transformation description and is not suitable for web design.
The description of how to move the data is done in content injection sheets. They have a grammar that is mostly <source XPath> <action> <target XPath>. The actions are those specified by TAL.
The idea for content injection sheets came from seeing a web designer adding an image to a page with css. I realized that he was actually injecting content. Since the semantics are similiar cjs sheets do resemble css.
This demonstrates the use of the Cindy Apache2 module and SSI for building a static website. As you see you get an albeit limited CMS. Cindy is used to surround all pages with a constant frame and to create a menu. You can look at the unmodified pages (such as this page or its directory index) by adding a GET parameter cindy=no.
All static pages are used as data for the template frame.html (Check the source). Their title is moved to the frames title. Their body is moved into the frames <div id="main">. This strips the header and enables using a static frame around all pages. This frame includes the menu. Both is done by this simple cjs sheet.
The directory indexes are parsed as data and are then recursively included via SSI. Parsing the directory indexes generated by mod_autoindex is done using a more complex cjs sheet. For each directory found in such an index a SSI include for that directory is generated. The result is a nested list, that is displayed as a menu using a css stylesheet (Stu Nicholis Ultimate menu v2 in this demo).
The advantage of using apache directory indexes is that things a user is not allowed to see are automatically removed. So if HTTP authentication is required for a directory, it appears in the menu when the user authenticates.
How content injection is done is controlled from .htaccess. For every file Cindy needs to know template, data and injection sheet. These are communicated to the request handler by environment variables with the prefix CINDY. Static values are set with SetEnv while dynamic values are set with RewriteRule ... [E:..]. Note the usage of IndexIgnore to keep files or directories out of the menu.