[z3-checkins] r54962 - in z3/deliverance/sandboxes/paul/dvng: . step01 step02 step03

paul at codespeak.net paul at codespeak.net
Mon May 19 21:35:19 CEST 2008


Author: paul
Date: Mon May 19 21:35:17 2008
New Revision: 54962

Added:
   z3/deliverance/sandboxes/paul/dvng/conf.py
   z3/deliverance/sandboxes/paul/dvng/index.rst
   z3/deliverance/sandboxes/paul/dvng/step01/
   z3/deliverance/sandboxes/paul/dvng/step01.rst
   z3/deliverance/sandboxes/paul/dvng/step01/content.html
   z3/deliverance/sandboxes/paul/dvng/step01/content.xml   (contents, props changed)
   z3/deliverance/sandboxes/paul/dvng/step01/dvfinalstage.xsl
   z3/deliverance/sandboxes/paul/dvng/step01/result.html
   z3/deliverance/sandboxes/paul/dvng/step01/theme.html
   z3/deliverance/sandboxes/paul/dvng/step01/xform.py
   z3/deliverance/sandboxes/paul/dvng/step02/
   z3/deliverance/sandboxes/paul/dvng/step02.rst
   z3/deliverance/sandboxes/paul/dvng/step02/compiler.xsl
   z3/deliverance/sandboxes/paul/dvng/step02/content.html
   z3/deliverance/sandboxes/paul/dvng/step02/dvfinalstage.xsl
   z3/deliverance/sandboxes/paul/dvng/step02/rules.xml
   z3/deliverance/sandboxes/paul/dvng/step02/theme.html
   z3/deliverance/sandboxes/paul/dvng/step02/xform-a.py
   z3/deliverance/sandboxes/paul/dvng/step02/xform.py
   z3/deliverance/sandboxes/paul/dvng/step03/
   z3/deliverance/sandboxes/paul/dvng/step03.rst
   z3/deliverance/sandboxes/paul/dvng/step03/compiler.xsl
   z3/deliverance/sandboxes/paul/dvng/step03/content2.html
   z3/deliverance/sandboxes/paul/dvng/step03/dvfinalstage-a.xsl
   z3/deliverance/sandboxes/paul/dvng/step03/dvfinalstage-b.xsl
   z3/deliverance/sandboxes/paul/dvng/step03/rules.rng
   z3/deliverance/sandboxes/paul/dvng/step03/rules.xml
   z3/deliverance/sandboxes/paul/dvng/step03/theme2.html
   z3/deliverance/sandboxes/paul/dvng/step03/xform.py
Log:
Source code

Added: z3/deliverance/sandboxes/paul/dvng/conf.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/conf.py	Mon May 19 21:35:17 2008
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+#
+# Sample Stample documentation build configuration file, created by
+# sphinx-quickstart on Sun May 11 11:35:19 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+#extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = 'DVNG Walkthrough'
+copyright = '2008, Paul Everitt'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '0.0.0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.0.0.1'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directories, that shouldn't be searched
+# for source files.
+#exclude_dirs = []
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# The name of an image file (within the static path) to place at the top of
+# the sidebar.
+#html_logo = None
+	
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'

Added: z3/deliverance/sandboxes/paul/dvng/index.rst
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/index.rst	Mon May 19 21:35:17 2008
@@ -0,0 +1,70 @@
+===========================================
+DVNG - Rewriting the XSLT Renderer
+===========================================
+
+Deliverance is a simple system for applying a common look-and-feel to all
+pages across site, no matter what system generated the pages. Currently,
+Deliverance has two modes it uses to render:
+
+  - The Python Renderer uses lxml to manipulate HTML node trees during a
+    request. This is the default renderer and the most supported.
+
+  - The XSLT Renderer generates an XSLT stylesheet that is applied to the
+    content, transforming the content page into a themed result. For this
+    renderer, XSLT is nothing but an internal, intermediate language:
+    Deliverance integrators need never see a single line of XSLT.
+
+DVNG is an experiment in rewriting the XSLT Renderer to achieve some new
+goals, while also prototyping the redesign of the Deliverance
+specification.
+
+Design and Goals
+------------------------
+
+In a nutshell, DVNG uses a multistage approach to generate a standalone
+XSLT stylesheet. The stages break the work into smaller, more easily
+debugged chunks, using a combination of Pythonic lxml programming and
+XSLT transformation to produce the final stage.
+
+This final stage can be run with any XSLT processor and is no longer tied
+to the original theme, rules, or Deliverance processing logic. Stated
+differently, the final stage could be checked into Subversion and used
+without even installing Deliverance on a production server.
+
+The goals include:
+
+- *Speed*. The current Deliverance renderers do a lot of work on each
+  request. DVNG plans to do a lot of work once, with the result being
+  usable not just between requests, but for as long as the theme and
+  rules do not change.
+
+- *Reliability*.  Much less complex.
+
+- *Debuggability*.
+
+- *Extensibility*.
+
+About This Document
+---------------------------
+
+This walkthrough is aimed first at the Deliverance mailing list, where we
+are considering design of the new specification and implementations.
+
+As such, we'll gradually build the result, step by step, to show the
+thinking that went into this approach. In some ways, this is an advocacy
+document, meant not just to explain, but also to persuade. Apologies in
+advance. (wink)
+
+Requirements
+--------------------
+
+Some of the work produced herein can run directly in Firefox 3.0b5+.
+Others can be run with a fairly recent version of ``xsltproc``. For the
+complete effect, though, you might want to install the Python lxml
+extension, version 2.0 or higher.
+
+.. toctree::
+
+	step01.rst
+	step02.rst
+	step03.rst
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step01.rst
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01.rst	Mon May 19 21:35:17 2008
@@ -0,0 +1,146 @@
+===========================================
+Step 01 - The Minimum
+===========================================
+
+We have a number of things to introduce for DVNG. So in this first step
+we take it pretty easy:
+
+- View and explain the final step in the production of a "compiled
+  themeset"
+
+- See how to run that compiled themeset on a content page
+
+Sample Data and Desired Output
+----------------------------------------
+
+In this first step, we'll support a very simple case: taking a "page
+heading" from the content and putting in the right box of the theme.
+
+For this step, imagine a very simple theme:
+
+.. literalinclude:: step01/theme.html
+	:language: html
+	:linenos:
+	
+And a very simple content page:
+
+.. literalinclude:: step01/content.html
+	:language: html 
+	:linenos:
+
+On line 6 of the theme, we want to replace the ``Theme Page Heading``
+text inside the ``<h1>`` with the ``DVNG Walkthrough`` content from line
+2 of the content page. That is, we want the following markup as the
+themed result:
+
+.. literalinclude:: step01/result.html
+	:language: html 
+	:linenos:
+
+Compilation
+------------------
+
+Under Deliverance, we would effect this transform by writing a rules
+file and doing the Deliverance processing.
+
+For DVNG, though, let's invert the thinking: let's start at the end and
+discuss what should the "final stage" XSLT look like? We can then work
+the problem backwards, writing stages that gradually produce that
+result, using the theme file and the rules file as the ultimate source.
+
+Here is an XSLT that prepares the way for later DVNG features:
+
+.. literalinclude:: step01/dvfinalstage.xsl
+	:language: xslt 
+	:linenos:
+
+There are 3 major sections to this:
+
+#. *Compiled Theme*. Lines 4-19 handle the compiled theme, generated by
+   earlier stages of DVNG. We first make an ``xsl:variable`` that holds
+   the mixture of HTML (from the theme file) and XSLT instructions (by
+   way of the rules file). We then use EXSLT to turn this into a named
+   nodeset that we can do further work on. Note that, when the variable
+   is initialized, the XSLT instructions are processed and thus, the
+   theme processes the content.
+
+#. *Start processing*. Line 20 is the XSLT rule that matches on the top
+   of the incoming content page, and thus, the start of processing the
+   transform. This template rule is very simple: grab the first node in
+   the *compiled theme* (instead of the incoming content page), start
+   processing, and thus pass control over to other XSLT templates.
+
+#. *Identity transform*. Lines 25-28 are the classic XSLT pattern known
+   as the "identity transform." This least-common-denominator rule
+   matches when nothing else does, and simply copies the result to the
+   output, recursively.
+
+So in a nutshell:
+
+- At runtime, create a variable that holds the themed content.
+
+- Copy that content to the result document.
+
+Running
+----------------
+
+You can try this quite easily using ``xsltproc`` in the ``step01``::
+
+	$ /usr/bin/xsltproc dvfinalstage.xsl content.html
+	<html>
+	<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>Theme Page Title</title>
+	</head>
+	<body>
+	<h1 id="pageheading">
+	    DVNG Walkthrough
+	</h1>
+	<p>Some theme text here.</p>
+	</body>
+	</html>
+
+You can also time the performance::
+
+	$ /usr/bin/xsltproc --repeat --timing dvfinalstage.xsl content.html 
+	Parsing stylesheet dvfinalstage.xsl took 0 ms
+	Parsing document content.html took 0 ms
+	Applying stylesheet 20 times took 6 ms
+	<html>
+	<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>Theme Page Title</title>
+	</head>
+	<body>
+	<h1 id="pageheading">
+	    DVNG Walkthrough
+	</h1>
+	<p>Some theme text here.</p>
+	</body>
+	</html>
+	
+Additionally,here is a Python script that uses lxml to apply the result 
+to the content:
+
+
+.. literalinclude:: step01/xform.py
+	:linenos:
+
+And finally, you can point Firefox (version 3.0b5 or later) or Safari at
+the ``step01\content.xml``. It will transform the input using the XSLT
+and let you view the results of your compiled themeset.
+
+.. note::
+
+  How did that work? Firefox (and IE, and Opera, and Safari) have long
+  supported client-side XSLT. You send back an XML document with a
+  "processing instruction" that points at a CSS or XSLT to help
+  visualize the XML. In the case of XSLT, the browser transforms the XML
+  document into HTML and shows the result.
+
+  We had to copy the ``content.html`` to a ``content.xml`` to trick
+  Firefox/Safari into opening the file in XML mode.
+
+  Why such a recent Firefox? Because this experiment relies on features
+  from the EXSLT extensions to XSLT, which are only recently supported
+  on Firefox.
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step01/content.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01/content.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,3 @@
+<div id="page-content">
+    <h1>DVNG Walkthrough</h1>
+</div>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step01/content.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01/content.xml	Mon May 19 21:35:17 2008
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="dvfinalstage.xsl"?>
+<div id="page-content">
+    <h1>DVNG Walkthrough</h1>
+</div>

Added: z3/deliverance/sandboxes/paul/dvng/step01/dvfinalstage.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01/dvfinalstage.xsl	Mon May 19 21:35:17 2008
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:exsl="http://exslt.org/common" version="1.0">
+    <xsl:variable name="compiledtheme">
+        <!-- This is generated from earlier stages -->
+        <html>
+            <head>
+                <title>Theme Page Title</title>
+            </head>
+            <body>
+                <h1 id="pageheading">
+                    <!-- The rules file determines the XPath here -->
+                    <xsl:value-of select="/div[@id='page-content']"/>
+                </h1>
+                <p>Some theme text here.</p>
+            </body>
+        </html>
+    </xsl:variable>
+    <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+    <xsl:template match="/">
+        <!-- Match on the top of the content page, then switch  
+        processing control to the nodes in the compiled theme. -->
+        <xsl:apply-templates select="$ct/*"/>
+    </xsl:template>
+    <xsl:template match="node()|@*">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+        </xsl:copy>
+    </xsl:template>
+</xsl:stylesheet>

Added: z3/deliverance/sandboxes/paul/dvng/step01/result.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01/result.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,12 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Theme Page Title</title>
+</head>
+<body>
+<h1 id="pageheading">
+    DVNG Walkthrough
+</h1>
+<p>Some theme text here.</p>
+</body>
+</html>

Added: z3/deliverance/sandboxes/paul/dvng/step01/theme.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01/theme.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,9 @@
+<html>
+    <head>
+        <title>Theme Page Title</title>
+    </head>
+    <body>
+        <h1 id="pageheading">Theme Page Heading</h1>
+        <p>Some theme text here.</p>
+    </body>
+</html>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step01/xform.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step01/xform.py	Mon May 19 21:35:17 2008
@@ -0,0 +1,11 @@
+from lxml import etree
+
+def main():
+	contentdoc = etree.ElementTree(file="content.html")
+	xsldoc = etree.ElementTree(file="dvfinalstage.xsl")
+	processor = etree.XSLT(xsldoc)
+	result = processor(contentdoc)
+	print result
+	
+if __name__ == "__main__":
+	main()

Added: z3/deliverance/sandboxes/paul/dvng/step02.rst
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02.rst	Mon May 19 21:35:17 2008
@@ -0,0 +1,191 @@
+===========================================
+Step 02 - A "Compiler" for DVNG
+===========================================
+
+We saw in Step 01 how an XSLT could be produced that handled the simple
+case. Before going into more complicated cases, though, let's work the
+problem backwards. Remember, we want to start with the ``theme.html``
+file on disk with a ``rules.xml`` file lying around somewhere.
+
+In this step we'll work on:
+
+- An XSLT "compiler" that produces the ``dvfinalstage.xsl`` in Step 01
+
+- An input document for that XSLT that is the theme file...with a little
+  help from lxml
+
+- And of course, the rules file
+
+Sample Data and Desired Output
+----------------------------------------
+
+We'll use the (almost) same ``theme.html`` and ``content.html`` files
+from Step 01. Additionally, we want to use the beginnings of a rules
+file:
+
+.. literalinclude:: step02/rules.xml
+	:language: xml
+	:linenos:
+
+This is the minimum to express our goal, which is to keep everything in
+the theme but replace the theme's "pageheading" text with text from the
+content page. We'll add other rules and more rule attributes later.
+
+Regarding the desired output, this is simple: we want this stage to
+produce the ``dvfinalstage.xsl`` as shown in Step 01. Again, once we
+have that XSLT, we can use it anywhere that supports XSLT processing
+(albeit with EXSLT extensions.)
+
+Overview and theme "hints"
+-------------------------------
+
+Our strategy in this stage goes a little bit like this:
+
+- Start with a "hinted" theme file (explained next)
+
+- Have a `compiler.xsl` that converts the theme file into the final
+  stage
+
+- This compiler.xsl also reads in the rules file
+
+This stage expects the theme file to have some "hints" in it. Namely, we
+expect an earlier stage to have found and marked the nodes in the theme
+that were matched by a rule's @themeid attribute. As an example::
+
+  <h1 id="pageheading" dv:ruleid="1" dv:ruletype="replace">Theme 
+  Page Heading</h1>
+
+This adds two attributes to the spot in the theme where a rule should
+operate:
+
+- dv:ruleid points to the rule number (position()) that matched this
+  theme node
+
+- dv:ruletype indicates what kind of rule (append, prepend, etc.) was
+  matched. The reason for this will be explained when we look at the
+  compiler.
+
+Compilation
+----------------------
+
+Now let's take a look at the "compiler", which is nothing more than an
+XSLT:
+
+.. literalinclude:: step02/compiler.xsl
+	:language: xslt
+	:linenos:
+
+Walking through the thinking of the compiler:
+
+#. **Lines 2-5**. Lots of namespaces in here. These point to extended
+   functionality from the EXSLT (exslt.org) standard add-ons. Also, we
+   need a trick to make it easy to generate XSLT nodes in the output 
+   without interpreting them as part of the transform. namespace-alias,
+   in combination with binding the processing to the "x:" prefix, does
+   this.
+
+#. **Line 7**. Read the rules file in as an input document in addition
+   to the ``theme.html`` that will be the regular input document.
+
+#. **Lines 9-24**. Generate most of the boilerplate for the desired
+   output, which is the ``dvfinalstage.xsl`` in Step 01.
+
+#. **Line 12**. Pass control back to the XSLT processor, which starts
+   recursively processing all the nodes in the input document
+   (theme.html), looking for rules to match.
+
+#. **Lines 25-34**. Ah *HA*! The heart of the matter. Match on an HTML
+   node in the theme that has those funny hints. In this case, handle a
+   case where we are supposed to do a Deliverance "replace". This is,
+   essentially, the implementation of a Deliverance "rule".
+
+#. **Line 27**. Copy all the attributes from the theme node to the
+   output, *except* those funny "hint" attributes in the ``dv:``
+   namespace.
+
+#. **Lines 28-32**. The ``replace`` rule says to take out all the theme
+   node's children and insert all the nodes matched in the content. This
+   maps to an ``<xsl:value-of select="somexpath">`` expression, so
+   create one of those. Use a convenience function (``dv:getrule()``, 
+   explained next) to grab the rule's ``@content`` attribute for the
+   value of "somexpath".
+
+#. **Lines 35-37**. Define an extension function to make it easy to find
+   the rule that placed the hints in the theme node.
+
+Running
+----------------
+
+Again, you can try this quite easily using ``xsltproc`` in the
+``step02`` directory. Remember to run it against the ``theme.html``
+document::
+
+	$ /usr/bin/xsltproc dvfinalstage.xsl theme.html
+	<?xml version="1.0"?>
+	<xsl:stylesheet xmlns:exsl="http://exslt.org/common"
+	 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	 xmlns:dv="http://openplans.org/deliverance"
+	 xmlns:dyn="http://exslt.org/dynamic" version="1.0">
+	  <xsl:variable name="compiledtheme">
+	    <html>
+	    <head>
+	        <title>Theme Page Title</title>
+	    </head>
+	    <body>
+	        <h1 id="pageheading"><xsl:value-of select="/div[@id='page-content']/h1"/></h1>
+	    </body>
+	</html>
+	  </xsl:variable>
+	  <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+	  <xsl:template match="/">
+	    <xsl:apply-templates select="$ct/*"/>
+	  </xsl:template>
+	  <xsl:template match="node()|@*">
+	    <xsl:copy>
+	      <xsl:apply-templates select="node()|@*"/>
+	    </xsl:copy>
+	  </xsl:template>
+	</xsl:stylesheet>
+	
+You can run this in, save to a file, and then run the final stage::
+
+	$ /usr/bin/xsltproc compiler.xsl theme.html > dvfinalstage.xsl
+	$ /usr/bin/xsltproc dvfinalstage.xsl content.html 
+	<html>
+	<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>Theme Page Title</title>
+	</head>
+	<body>
+	<h1 id="pageheading">DVNG Walkthrough</h1>
+	<p>Some theme text here.</p>
+	</body>
+	</html>
+
+This is the output we expected: the ``<h1>`` gets its value from the
+content page instead of the theme.
+
+Python For First Stage
+------------------------------
+
+We will start with a Python file that does the same work as the
+``xsltproc`` example:
+
+.. literalinclude:: step02/xform-a.py
+	:language: python
+	:linenos:
+
+This example uses a small class, instead of one big function.
+
+Next up, we need to add the logic that produces the "hints" in the
+theme. Just for fun, we turn the result of the first stage into the
+final processor and use it to theme some content:
+
+.. literalinclude:: step02/xform.py
+	:language: python
+	:linenos:
+
+This has plenty of docstrings and comments, but let's walk through the
+lines:
+
+#. **Line 4-6**.  Setup some XML namespace-oriented constants.

Added: z3/deliverance/sandboxes/paul/dvng/step02/compiler.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/compiler.xsl	Mon May 19 21:35:17 2008
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<x:stylesheet xmlns:x="http://www.w3.org/1999/XSL/Transform" xmlns:func="http://exslt.org/functions"
+    xmlns:dv="http://openplans.org/deliverance" xmlns:xsl="anything" extension-element-prefixes="func"  
+    xmlns:dyn="http://exslt.org/dynamic" xmlns:exsl="http://exslt.org/common" version="1.0">
+    <x:namespace-alias stylesheet-prefix="xsl" result-prefix="x"/>
+    <x:output indent="yes" method="xml"/>
+    <x:variable name="rf" select="document('rules.xml')/*"/>
+    <x:variable name="dvuri">http://openplans.org/deliverance</x:variable>
+    <x:template match="/">
+        <xsl:stylesheet xmlns:exsl="http://exslt.org/common" version="1.0">
+            <xsl:variable name="compiledtheme">
+                <x:apply-templates select="node()|@*"/>
+            </xsl:variable>
+            <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+            <xsl:template match="/">
+                <xsl:apply-templates select="$ct/*"/>
+            </xsl:template>
+            <xsl:template match="node()|@*">
+                <xsl:copy>
+                    <xsl:apply-templates select="node()|@*"/>
+                </xsl:copy>
+            </xsl:template>
+        </xsl:stylesheet>
+    </x:template>
+    <x:template match="node()[@dv:ruletype='replace']">
+        <x:copy>
+            <x:apply-templates select="@*[namespace-uri()!=$dvuri]"/>
+            <xsl:value-of>
+                <x:attribute name="select">
+                    <x:value-of select="dv:getrule()/@content"/>
+                </x:attribute>
+            </xsl:value-of>
+        </x:copy>
+    </x:template>
+    <func:function name="dv:getrule">
+        <func:result select="$rf/*[position()=current()/@dv:ruleid]"/>
+    </func:function>
+    <x:template match="node()|@*">
+        <x:copy>
+            <x:apply-templates select="node()|@*"/>
+        </x:copy>
+    </x:template>
+</x:stylesheet>

Added: z3/deliverance/sandboxes/paul/dvng/step02/content.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/content.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,3 @@
+<div id="page-content">
+    <h1>DVNG Walkthrough</h1>
+</div>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step02/dvfinalstage.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/dvfinalstage.xsl	Mon May 19 21:35:17 2008
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dv="http://openplans.org/deliverance" xmlns:dyn="http://exslt.org/dynamic" version="1.0">
+  <xsl:variable name="compiledtheme">
+    <html>
+    <head>
+        <title>Theme Page Title</title>
+    </head>
+    <body>
+        <h1 xmlns:ns0="http://openplans.org/deliverance" id="pageheading"><xsl:value-of select="/div[@id='page-content']/h1"/></h1>
+        <p>Some theme text here.</p>
+    </body>
+</html>
+  </xsl:variable>
+  <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+  <xsl:template match="/">
+    <xsl:apply-templates select="$ct/*"/>
+  </xsl:template>
+  <xsl:template match="node()|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="node()|@*"/>
+    </xsl:copy>
+  </xsl:template>
+</xsl:stylesheet>
+

Added: z3/deliverance/sandboxes/paul/dvng/step02/rules.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/rules.xml	Mon May 19 21:35:17 2008
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rules xmlns="http://openplans.org/deliverance">
+    <replace 
+		theme="/html/body/h1[@id='pageheading']" 
+		content="/div[@id='page-content']/h1"/>
+</rules>

Added: z3/deliverance/sandboxes/paul/dvng/step02/theme.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/theme.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,9 @@
+<html xmlns:dv="http://openplans.org/deliverance">
+    <head>
+        <title>Theme Page Title</title>
+    </head>
+    <body>
+        <h1 id="pageheading" dv:ruleid="1" dv:ruletype="replace">Theme Page Heading</h1>
+        <p>Some theme text here.</p>
+    </body>
+</html>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step02/xform-a.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/xform-a.py	Mon May 19 21:35:17 2008
@@ -0,0 +1,20 @@
+from lxml import etree
+
+class DVNG:
+	
+	def __init__(self):
+		self.compilerdoc = etree.ElementTree(file="compiler.xsl")
+		self.compiler = etree.XSLT(self.compilerdoc)
+		
+	def __call__(self, themefn):
+		themedoc = etree.ElementTree(file=themefn)
+		result = self.compiler(themedoc)
+		return result
+		
+def main():
+	dvng = DVNG()
+	result = dvng("theme.html")
+	print result
+	
+if __name__ == "__main__":
+	main()

Added: z3/deliverance/sandboxes/paul/dvng/step02/xform.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step02/xform.py	Mon May 19 21:35:17 2008
@@ -0,0 +1,54 @@
+from lxml import etree
+
+# Constants
+DV_NAMESPACE = "http://openplans.org/deliverance"
+DV = "{%s}" % DV_NAMESPACE
+NSMAP = {"dv": DV_NAMESPACE}
+
+class DVNG:
+	
+	compilerfn = "compiler.xsl"
+	
+	def compileTheme(self, themefn, rulesfn):
+		"""Given theme and rule files, make a compiled themeset"""
+
+		# Make the compiler XSLT
+		compilerdoc = etree.ElementTree(file=self.compilerfn)
+		compiler = etree.XSLT(compilerdoc)
+
+		# Load the theme doc and rules doc
+		self.themedoc = etree.ElementTree(file=themefn)
+		self.rulesdoc = etree.ElementTree(file="rules.xml")
+		
+		# Iterate over the rules, find the theme nodes that
+		# match, and add the "hint" attributes.
+		position = 1
+		for rule in self.rulesdoc.xpath("/*/*", namespaces=NSMAP):
+			themexpath = rule.get("theme")
+			ruletype = rule.tag.split("}")[1]
+			for themenode in self.themedoc.xpath(themexpath):
+				themenode.set(DV + "ruleid", str(position))
+				themenode.set(DV + "ruletype", ruletype)
+			position = position +1
+
+		# themedoc now hacked to provide hints, so transform.
+		self.finalstage = compiler(self.themedoc)
+		self.processor = etree.XSLT(self.finalstage)
+		
+	def __call__(self, contentfn):
+		"""Apply a compiled themeset against a contentdoc"""
+
+		# Turn the result into a processor
+		content = etree.ElementTree(file=contentfn)
+		result = self.processor(content)
+		
+		return result		
+				
+def main():
+	dvng = DVNG()
+	dvng.compileTheme("../step01/theme.html", "rules.xml")
+	result = dvng("../step01/content.html")
+	return result
+	
+if __name__ == "__main__":
+	print main()

Added: z3/deliverance/sandboxes/paul/dvng/step03.rst
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03.rst	Mon May 19 21:35:17 2008
@@ -0,0 +1,291 @@
+===========================================
+Step 03 - Multi-theme support
+===========================================
+
+We've come quite a way so far. Although only for one kind of theme rule,
+we have support for processing a theme and rule file, then applying the
+theme to a content page.
+
+DVNG, though, can serve as a way to investigate new capabilities for
+Deliverance. Theming different pages in different ways is one of the
+biggest points under consideration for Deliverance. In this step
+investigate it:
+
+- Support theme switching in the ``dvfinalstage.xsl`` compiled themeset
+
+- Extend the compiler to support a rules file that specifies themes and
+  conditions
+
+- Provide rich information from the environment, such as HTTP headers,
+  for theme switching
+
+To do this, we'll gradually build up the support working backwards from
+the "compiled themeset".
+
+Sample Data and Desired Output
+----------------------------------------
+
+For our main theme, we'll continue using ``step01/theme.html``. We'll
+leave the file in that directory, as well as ``step01/content.html`` as
+an example of a content page that should be styled with that theme.
+
+We'll also introduce a second theme, one that includes a table layout
+with a left-column navigation:
+
+.. literalinclude:: step03/theme2.html
+	:language: html
+	:linenos:
+
+We will use ``step03/content2.html`` to represent a content page that
+should be themed with Theme 2.
+
+.. literalinclude:: step03/content2.html
+	:language: html
+	:linenos:
+	
+This is a very different content page:
+
+- It looks more like a full HTML page, with an ``<html>`` root node
+
+- It's more semantic-oriented: the ``<title>`` is in the ``<title>``,
+  not also repeated as an ``<h1>`` in the ``<body>``.
+
+- There is some document-ish content in the ``<body>``.
+
+- And key to our scenario, we pack in some information about the
+  "section" that the content page occurs in, as a ``<meta>`` element in
+  the ``<head>``. We'll use this to use a different theme, one for
+  subordinate pages.
+
+For the desired output, we want the first theme to do as before, but
+also take the ``<title>`` from the content page. The second theme,
+though, should do a bit more:
+
+- Merge the content's ``<title>`` into both the ``<title>`` of the
+  themed result and the ``<h1>`` heading
+
+- Copy everything from the ``<body>`` of the content into the
+  "pagecontent" of the themed result
+
+
+Compiled Themeset
+-----------------------
+
+As before, the goal is to have an XSLT transform that is self-contained
+and can be used in any context that supports applying XSLT
+transformations.
+
+Using ``step01/dvfinalstage.xsl`` as the starting point, let's add
+support for multiple themes. First up:
+
+.. literalinclude:: step03/dvfinalstage-a.xsl
+	:language: xslt
+	:linenos:
+
+#. **Lines 4-49**. Bind a theme to a variable.
+
+#. **Line 7**. The key to multitheme: use ``<xsl:choose>`` to select
+   which theme to bind to the variable. In this case, if the content
+   page has a ``<meta>`` tag named ``dv.section``, then use the theme 
+   in that ``<xsl:when>``.
+
+#. **Line 33**. If nothing else matches, use the final theme.
+
+Everything else in the compiled theme is the same as in Step 01.
+
+
+Running Part A
+-------------------
+
+We now have support in the final stage for multiple themes. How can we
+run it?  Same as before::
+
+	$ xsltproc dvfinalstage-a.xsl content2.html 
+	<html>
+	<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>A Deeper Look At DVNG</title>
+	</head>
+	<body><table border="0"><tr>
+	<td><h2>Navigation</h2></td>
+	<td>
+	<h1 id="pageheading">A Deeper Look At DVNG</h1>
+	<div id="pagecontent">
+	<p>I have some content <em>in here</em> to merge.</p>
+	<p>Perhaps an image will be in here later.</p>
+	</div>
+	</td>
+	</tr></table></body>
+	</html>
+
+	$ xsltproc dvfinalstage-a.xsl ../step01/content.html 
+	<html>
+	<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>DVNG Walkthrough</title>
+	</head>
+	<body>
+	<h1 id="pageheading">DVNG Walkthrough</h1>
+	<p>Some theme text here.</p>
+	</body>
+	</html>
+
+As you can see, the content in the first page (the ``<meta>`` tag)
+triggers the table-based theme. The performance is the same: 20
+transforms in 7 milliseconds.
+
+
+Theme Choice From Other Data
+-------------------------------------
+
+In this first case, we chose the theme based on information *in* the
+content page. But what if we want to choose from information in the URL,
+an HTTP header such as the content type, etc.?
+
+We'll add support for this in a relatively simple way: using XSLT
+*parameters*, or arguments the XSLT processor can supply to the
+transform. At the top of ``step03/dvfinalstage-b.xsl`` we see::
+
+	<xsl:param name="req.domain_url">look-at-me.com</xsl:param>
+
+This "declares" a transformation parameter and assigns a default value.
+
+.. note::
+
+	The ``req`` sure looks a lot like WebOb, right? Yes, the idea is 
+	to match the documentation for WebOb and have it able to 
+	supply values easily as parameters. In this case, ``domain_url``   
+	isn't something provided by WebOb (as it isn't part of the 
+	WSGI spec). Perhaps we can add it to WebOb.
+	
+	Also, note that use of parameters places more work on the 
+	XSLT environment that will apply the stylesheet.  Use of 
+	this feature (themeswitching based on the environment instead 
+	of content) likely means a compiled themeset that only works 
+	in Deliverance.
+
+The test condition on line 8 then changes. Instead choosing a template
+based on nodes in the content page, we choose content based on the value
+of the parameter::
+
+	<xsl:when test="$req.domain_url='look-at-me.com'">
+
+How will we implement this? That's the topic of the next section, but in
+summary:
+
+- The rules file will indicate where a certain condition will match
+
+- Based on what the rules file asks for, the ``compiler.xsl`` will put
+  ``<xsl:param>`` declarations in the compiled themeset
+  (``dvfinalstage.xsl``)
+
+- During operation, an XSLT processor will be expected to pass values to
+  this parameter to change the default value on a per-request basis
+
+You can run this with ``xsltproc`` as follows::
+
+	$ xsltproc --stringparam req.domain_url foo.com dvfinalstage-b.xsl content2.html
+
+The ``--stringparam`` is a way to pass a parameter value on the
+commandline. In lxml you pass keyword parameters to the ``XSLT()``
+function, as we'll see in the next section.
+
+
+Rulefile Support For Theme Switching
+--------------------------------------------
+
+We want theme switching to be declarative. We don't want Deliverance
+users to express it in Python and we definitely don't want them to
+express it in XSLT.
+
+That means support in the ``rules.xml`` file.  For example:
+
+.. literalinclude:: step03/rules.xml
+	:language: xml
+	:linenos:
+
+The rules file has more features now:
+
+#.	**Line 1**.  We wrap everything in a ``<themeset>`` to contain 
+   	each defined theme.
+
+#. 	**Lines 4-15**. A ``<theme>`` contains an ``@href`` pointing to 
+	the HTML file, a ``<match>`` which defines any of the conditions 
+	to which this applies, and a ``<rules>`` which contains the 
+	Deliverance rules.  Note that precedence matters: the first 
+	``<theme>`` containing a ``<match>`` that matches will be 
+	triggered.
+
+#. 	**Line 7-8**. If the content contains a ``<meta>`` tag of
+	``dv.section`` **OR** there the ``Request`` has a ``domain_url`` 
+	value equal to ``look-at-me.com``, then use this theme. Note: 
+	we can map to XPath string functions such as contains, 
+	starts-with, and substring if we find a suitable expression 
+	language.
+
+#. 	**Lines 10-14**. The rules, as before.
+
+#. 	**Lines 16-22**. This last theme has no ``<match>`` (which 
+	is optional), indicating that this is to be used when nothing 
+	else matches.
+
+Note also that we have added support for a minimal Relax NG schema that
+helps us validate our rules file. This is particularly helpful for tools
+(such as oXygen, which inserted that second line that references the
+schema) that do autocomplete, element documentation via the schema, and
+validate-as-you-type.
+
+Compiling the New Rule File
+-----------------------------------
+
+As in Step 02, we need a Python module which, given the theme files and
+the rules file, will generate the final stage XSLT.
+
+Along the way we'll make some changes to the Step 02 ``xform.py`` to
+make it more flexible:
+
+- Presume that the ``compiler.xsl`` is in the same directory as the
+  ``xform.py``.
+
+- Merge the rules and all themes into a single input document.
+
+- Let the ``theme/@href`` values define the location of the theme with
+  support for the ``here`` keyword.
+
+- Pass the location of the content file to be themed as a command-line
+  argument.
+
+- Load the content page using the HTML parser, in case it is messy.
+
+- Provide debug support to write to disk all the intermediate stages.
+
+This leads to a very different strategy for the Python module and the
+``compiler.xsl``. Let's start with the new Python module:
+
+.. literalinclude:: step03/xform.py
+	:language: python
+	:linenos:
+
+Here is the new compiler file:
+
+.. literalinclude:: step03/compiler.xsl
+	:language: xslt
+	:linenos:
+
+Running the module against one of the sample content pages is easy::
+
+	$ python ./xform.py content2.html 
+	<html>
+	<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>Second Theme Page Title</title>
+	</head>
+	<body><table border="0"><tr>
+	<td><h2>Navigation</h2></td>
+	<td>
+	<h1>A Deeper Look At DVNG</h1>
+	<div id="pagecontent">Theme content to replace.</div>
+	</td>
+	</tr></table></body>
+	</html>
+

Added: z3/deliverance/sandboxes/paul/dvng/step03/compiler.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/compiler.xsl	Mon May 19 21:35:17 2008
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<x:stylesheet xmlns:x="http://www.w3.org/1999/XSL/Transform"
+    xmlns:dv="http://openplans.org/deliverance" xmlns:xsl="anything"
+    xmlns:exsl="http://exslt.org/common" version="1.0">
+    <x:namespace-alias stylesheet-prefix="xsl" result-prefix="x"/>
+    <x:output indent="yes" method="xml"/>
+    <x:key name="getRule" match="dv:replace" use="@id"/>
+    <x:template match="/">
+        <xsl:stylesheet xmlns:exsl="http://exslt.org/common" version="1.0">
+            <!-- Find any <req> match rules and generate parameters -->
+            <x:apply-templates select="/*/*/dv:match/dv:req" mode="params"/>
+            <xsl:variable name="compiledtheme">
+                <xsl:choose>
+                    <!-- Based on certain conditions, use one of the themes -->
+                    <x:apply-templates select="/*/dv:theme"/>
+                </xsl:choose>
+            </xsl:variable>
+            <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+            <xsl:template match="/">
+                <xsl:apply-templates select="$ct/*"/>
+            </xsl:template>
+            <xsl:template match="node()|@*">
+                <xsl:copy>
+                    <xsl:apply-templates select="node()|@*"/>
+                </xsl:copy>
+            </xsl:template>
+        </xsl:stylesheet>
+    </x:template>
+    <!-- 
+        Theme switching.  If there are <match> conditions, make an 
+        <xsl:when> and put "or" between all the conditions.
+    -->
+    <x:template match="dv:theme[dv:match]">
+        <xsl:when>
+            <x:attribute name="test">
+                <x:for-each select="dv:match/*">
+                    <x:if test="position() > 1"> or </x:if>
+                    <x:apply-templates select="."/>
+                </x:for-each>
+            </x:attribute>
+            <x:apply-templates select="dv:source/*"/>
+        </xsl:when>
+    </x:template>
+    <x:template match="dv:theme[not(dv:match)]">
+        <xsl:otherwise>
+            <x:apply-templates select="dv:source/*"/>
+        </xsl:otherwise>
+    </x:template>
+    <!-- 
+        Handle the kinds of match conditions by generating predicates
+        to OR together in an <xsl:when>.
+    -->
+    <x:template match="dv:content">
+        <x:value-of select="."/>
+    </x:template>
+    <x:template match="dv:req">$req.<x:value-of select="@key"/>='<x:value-of select="."/>'</x:template>
+    <!-- 
+        Next up, support generating <xsl:param> nodes at the top of 
+        the XSLT, for cases where we themeswitch based on information
+        outside the content page (e.g. the headers.)
+    -->
+    <x:template match="dv:req" mode="params">
+        <xsl:param name="req.{@key}">
+            <x:value-of select="."/>
+        </xsl:param>
+    </x:template>
+    <!-- 
+        Now we have support for each kind of rule. 
+    -->
+    <x:template match="@ruletype[.='replace']">
+        <xsl:value-of>
+            <x:attribute name="select">
+                <x:value-of select="key('getRule',../@ruleid)/@content"/>
+            </x:attribute>
+        </xsl:value-of>
+    </x:template>
+    <!-- End implementation of rule types.  -->
+
+    <x:template match="*">
+        <!-- Translate the html nodes from the dv namespace into 
+        the null numespace -->
+        <x:element name="{local-name(.)}">
+            <x:choose>
+                <x:when test="@ruletype">
+                    <!-- This calls a handler for each ruletype -->
+                    <x:apply-templates select="@ruletype"/>
+                </x:when>
+                <x:otherwise>
+                    <x:apply-templates select="node()|@*"/>
+                </x:otherwise>
+            </x:choose>
+        </x:element>
+    </x:template>
+    <!-- 
+        Pass everything else through.
+    -->
+    <x:template match="@*">
+        <x:copy>
+            <x:apply-templates select="node()|@*"/>
+        </x:copy>
+    </x:template>
+    <x:template match="@ruleid|@ruletype"/>
+</x:stylesheet>

Added: z3/deliverance/sandboxes/paul/dvng/step03/content2.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/content2.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,10 @@
+<html>
+    <head>
+        <title>A Deeper Look At DVNG</title>
+        <meta name="dv.section" content="DVNG Articles"/>
+    </head>
+    <body>
+        <p>I have some content <em>in here</em> to merge.</p>
+        <p>Perhaps an image will be in here later.</p>
+    </body>
+</html>

Added: z3/deliverance/sandboxes/paul/dvng/step03/dvfinalstage-a.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/dvfinalstage-a.xsl	Mon May 19 21:35:17 2008
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:exsl="http://exslt.org/common" version="1.0">
+    <xsl:variable name="compiledtheme">
+        <xsl:choose>
+            <!-- Based on certain conditions, use one of the themes -->
+            <xsl:when test="/html/head/meta[@name='dv.section']">
+                <html>
+                    <head>
+                        <title>
+                            <xsl:value-of select="/html/head/title"/>
+                        </title>
+                    </head>
+                    <body>
+                        <table border="0">
+                            <tr>
+                                <td>
+                                    <h2>Navigation</h2>
+                                </td>
+                                <td>
+                                    <h1 id="pageheading">
+                                        <xsl:value-of select="/html/head/title"/>
+                                    </h1>
+                                    <div id="pagecontent">
+                                        <xsl:apply-templates select="/html/body/*"/>
+                                    </div>
+                                </td>
+                            </tr>
+                        </table>
+                    </body>
+                </html>
+            </xsl:when>
+            <xsl:otherwise>
+                <html>
+                    <head>
+                        <title>
+                            <xsl:value-of select="/div[@id='page-content']/h1"/>
+                        </title>
+                    </head>
+                    <body>
+                        <h1 id="pageheading">
+                            <xsl:value-of select="/div[@id='page-content']/h1"/>
+                        </h1>
+                        <p>Some theme text here.</p>
+                    </body>
+                </html>
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+    <xsl:template match="/">
+        <!-- Match on the top of the content page, then switch  
+        processing control to the nodes in the compiled theme. -->
+        <xsl:apply-templates select="$ct/*"/>
+    </xsl:template>
+    <xsl:template match="node()|@*">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+        </xsl:copy>
+    </xsl:template>
+</xsl:stylesheet>

Added: z3/deliverance/sandboxes/paul/dvng/step03/dvfinalstage-b.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/dvfinalstage-b.xsl	Mon May 19 21:35:17 2008
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:exsl="http://exslt.org/common" version="1.0">
+    <xsl:param name="req.domain_url">look-at-me.com</xsl:param>
+    <xsl:variable name="compiledtheme">
+        <xsl:choose>
+            <!-- Based on certain conditions, use one of the themes -->
+            <xsl:when test="$req.domain_url='look-at-me.com'">
+                <html>
+                    <head>
+                        <title>
+                            <xsl:value-of select="/html/head/title"/>
+                        </title>
+                    </head>
+                    <body>
+                        <table border="0">
+                            <tr>
+                                <td>
+                                    <h2>Navigation</h2>
+                                </td>
+                                <td>
+                                    <h1 id="pageheading">
+                                        <xsl:value-of select="/html/head/title"/>
+                                    </h1>
+                                    <div id="pagecontent">
+                                        <xsl:apply-templates select="/html/body/*"/>
+                                    </div>
+                                </td>
+                            </tr>
+                        </table>
+                    </body>
+                </html>
+            </xsl:when>
+            <xsl:otherwise>
+                <html>
+                    <head>
+                        <title>
+                            <xsl:value-of select="/div[@id='page-content']/h1"/>
+                        </title>
+                    </head>
+                    <body>
+                        <h1 id="pageheading">
+                            <xsl:value-of select="/div[@id='page-content']/h1"/>
+                        </h1>
+                        <p>Some theme text here.</p>
+                    </body>
+                </html>
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="ct" select="exsl:node-set($compiledtheme)"/>
+    <xsl:template match="/">
+        <!-- Match on the top of the content page, then switch  
+        processing control to the nodes in the compiled theme. -->
+        <xsl:apply-templates select="$ct/*"/>
+    </xsl:template>
+    <xsl:template match="node()|@*">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+        </xsl:copy>
+    </xsl:template>
+</xsl:stylesheet>

Added: z3/deliverance/sandboxes/paul/dvng/step03/rules.rng
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/rules.rng	Mon May 19 21:35:17 2008
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar 
+  xmlns="http://relaxng.org/ns/structure/1.0"
+  xmlns:dv="http://openplans.org/deliverance"
+  xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"
+  datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+    <start>
+        <element name="dv:themeset">
+            <oneOrMore>
+                <element name="dv:theme">
+                    <attribute name="href"/>
+                    <zeroOrMore>
+                        <element name="dv:match">
+                            <interleave>
+                                <zeroOrMore>
+                                    <element name="dv:content"><text/></element>                                    
+                                </zeroOrMore>
+                                <zeroOrMore>
+                                    <element name="dv:req">
+                                        <attribute name="key"/>
+                                        <text/>
+                                    </element>
+                                </zeroOrMore>
+                            </interleave>
+                        </element>
+                    </zeroOrMore>
+                    <element name="dv:rules">
+                        <interleave>
+                            <zeroOrMore>
+                                <element name="dv:replace">
+                                    <attribute name="theme"/>
+                                    <attribute name="content"/>
+                                </element>
+                            </zeroOrMore>
+                        </interleave>
+                    </element>
+                </element>
+            </oneOrMore>
+        </element>
+    </start>
+</grammar>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step03/rules.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/rules.xml	Mon May 19 21:35:17 2008
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<themeset xmlns="http://openplans.org/deliverance">
+    <theme href="file:///%(here)s/step03/theme2.html">
+        <match>
+            <!-- These are OR'd together -->
+            <content>/html/head/meta[@name='dv.section']</content>
+            <req key="domain_url">look-at-me.com</req>
+        </match>
+        <rules>
+            <replace 
+                theme="//td/h1[@id='pageheading']" 
+                content="/html/head/title"/>
+        </rules>        
+    </theme>
+    <theme href="file:///%(here)s/step01/theme.html">
+        <rules>
+            <replace 
+                theme="//h1[@id='pageheading']" 
+                content="/div[@id='page-content']/h1"/>
+        </rules>        
+    </theme>
+</themeset>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/step03/theme2.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/theme2.html	Mon May 19 21:35:17 2008
@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>Second Theme Page Title</title>
+    </head>
+    <body>
+        <table border="0">
+            <tr>
+                <td>
+                    <h2>Navigation</h2>
+                </td>
+                <td>
+                    <h1 id="pageheading">Theme Page Heading</h1>
+                    <div id="pagecontent">Theme content to replace.</div>
+                </td>
+            </tr>
+        </table>
+    </body>
+</html>

Added: z3/deliverance/sandboxes/paul/dvng/step03/xform.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/step03/xform.py	Mon May 19 21:35:17 2008
@@ -0,0 +1,134 @@
+import lxml.html
+from lxml import etree
+import os
+import sys
+
+# Constants
+DV_NAMESPACE = "http://openplans.org/deliverance"
+DV = "{%s}" % DV_NAMESPACE
+NSMAP = {"dv": DV_NAMESPACE}
+
+class DVNG:
+	
+	def __init__(self, heredir, rulesuri):
+
+		# Some paths and filenames
+		self.heredir = heredir
+		absdir = os.path.dirname(os.path.abspath(__file__))
+		self.compilerfn = os.path.join(absdir, "compiler.xsl")
+
+		# Make the compiler XSLT
+		self.compilerdoc = etree.ElementTree(file=self.compilerfn)
+		self.compiler = etree.XSLT(self.compilerdoc)		
+	
+		# Load the rules doc then the theme docs. We want 
+		# both the original (for later introspection), plus 
+		# a "compiled rules" which will act as the input document
+		# for the compilation transform.
+		self.origrulesdoc = etree.ElementTree(file=rulesuri)
+		self.cr = etree.ElementTree(file=rulesuri)
+		
+		# Add hints and load HTML source
+		self._makeRuleIds()
+		self._loadThemes()
+
+		# Themes now hacked to provide hints, so transform.
+		self.finalstage = self.compiler(self.cr)
+		self.processor = etree.XSLT(self.finalstage)
+
+	def __call__(self, contentfn):
+		"""Apply a compiled themeset against a contentdoc"""
+
+		# Turn the result into a processor
+		content = etree.ElementTree(file=contentfn)
+		kw = {'req.domain_url': 'look-at-me.com'}
+		result = self.processor(content, **kw)
+
+		return result		
+
+
+	def _loadThemes(self):
+		
+		# First, find all the <theme href=""> nodes, 
+		# retrieve the HTML, process it, and merge into the 
+		# compiled rules file.
+
+		for themeuri in self._getNode("/dv:themeset/dv:theme/@href"):
+			# Grab the dv:theme node, then its dv:match child
+			themenode = themeuri.getparent()
+			match = themenode.find(DV + "match")
+			
+			# Make nice URI to theme source HTML and retrieve
+			parturi = self._expandURI(themeuri)
+			themehtml = lxml.html.parse(parturi).getroot()
+			
+			# Find all theme nodes referenced by rules and put in
+			# hints
+			self._makeThemeHints(themehtml, themenode)
+			
+			# Graft in the hinted HTML source into the compiled rules
+			themesource = etree.SubElement(themenode, DV + "source")
+			themesource.append(themehtml)
+			
+	def _makeThemeHints(self, htmlroot, themenode):
+		"""Given raw HTML, add @ruleid and @ruletype to correct nodes"""
+		
+		for themexpath in self._getNode("dv:rules/*/@theme", themenode):
+			ruleid = themexpath.getparent().get("id")
+			ruletype = themexpath.getparent().tag.split("}")[1]
+			themenode = htmlroot.xpath(themexpath)[0]
+			themenode.set("ruleid", ruleid)
+			themenode.set("ruletype", ruletype)
+
+
+	def _makeRuleIds(self):
+		"""Put identifiers in rules to use as a primary key"""
+		
+		rulenum = 0
+		for rule in self._getNode("/dv:themeset/dv:theme/dv:rules/*"):
+				rulenum = rulenum + 1
+				ruleid = "r%s" % rulenum
+				rule.set("id", ruleid)
+		
+
+	def _getNode(self, xp, node=None):
+		"""Easier way to get namespaced XPaths on compiled rules doc"""
+		
+		if node is None:
+			# Allow passing a different starting point
+			node = self.cr
+			
+		return node.xpath(xp, namespaces=NSMAP)
+
+		
+	def _expandURI(self, themeuri):
+		"""Given a file:///%(here)s URI, return a usable reference"""
+		
+		fulluri = themeuri % {'here': self.heredir}
+		return fulluri[7:] # Cheat, as lxml.html can't do file:///	
+		
+	def debug(self):
+		"""Write out key artifacts to disk"""
+
+		self._writeDoc(self.cr, "cr.xml")
+		self._writeDoc(self.finalstage, "finalstage.xsl")
+
+		
+	def _writeDoc(self, doc, filename):
+		
+		f = open("xxx-%s" % filename, "w")
+		f.write(etree.tostring(doc, pretty_print=True))
+		f.close()
+
+				
+def main():
+	moduledir = os.path.dirname(os.path.abspath(__file__))
+	heredir = os.path.dirname(moduledir)[1:]
+	dvng = DVNG(heredir, "rules.xml")
+	dvng.debug()
+	result = dvng(sys.argv[1])
+	return result
+	
+if __name__ == "__main__":
+	result = main()
+	print result
\ No newline at end of file


More information about the z3-checkins mailing list