[z3-checkins] r29651 - in z3/deliverance/branches/namespaced: . content doc etc themes themes/simple

paul at codespeak.net paul at codespeak.net
Wed Jul 5 20:50:30 CEST 2006


Author: paul
Date: Wed Jul  5 20:50:26 2006
New Revision: 29651

Added:
   z3/deliverance/branches/namespaced/README.txt
   z3/deliverance/branches/namespaced/content/
   z3/deliverance/branches/namespaced/content/localhello.html
   z3/deliverance/branches/namespaced/deliverance.py
   z3/deliverance/branches/namespaced/doc/
   z3/deliverance/branches/namespaced/doc/NOTES.rst
   z3/deliverance/branches/namespaced/etc/
   z3/deliverance/branches/namespaced/etc/appmap.xml
   z3/deliverance/branches/namespaced/etc/themecontent.xml
   z3/deliverance/branches/namespaced/etc/themerules.xml
   z3/deliverance/branches/namespaced/modpython.conf
   z3/deliverance/branches/namespaced/modpython.py
   z3/deliverance/branches/namespaced/renderer.xsl
   z3/deliverance/branches/namespaced/themecompiler.xsl
   z3/deliverance/branches/namespaced/themes/
   z3/deliverance/branches/namespaced/themes/simple/
   z3/deliverance/branches/namespaced/themes/simple/sampletheme.xml
   z3/deliverance/branches/namespaced/themes/simple/simpletheme.css
Log:
First commit of refactored Deliverance, sans the content publishing part

Added: z3/deliverance/branches/namespaced/README.txt
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/README.txt	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,15 @@
+=======================================
+Deliverancy, high-speed themes for Zope
+=======================================
+
+Quick Start
+-----------
+
+1) Install lxml.
+
+2) cd to the directory containing this README.
+
+3) python ./deliverance.py
+
+This runs the timeit function, showing average time to apply a simple theme.
+

Added: z3/deliverance/branches/namespaced/content/localhello.html
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/content/localhello.html	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <title>Hello World</title>
+    </head>
+    <body>
+        <h1 id="pagetitle">Hello title</h1>
+        <p>Hello world</p>
+    </body>
+</html>
\ No newline at end of file

Added: z3/deliverance/branches/namespaced/deliverance.py
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/deliverance.py	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,156 @@
+
+import os
+from lxml import etree
+from time import time
+from lxml.etree import Namespace, ElementBase
+
+
+nsmap = {
+    "dv": "http://www.plone.org/deliverance",
+    "html": "http://www.w3.org/1999/xhtml",
+    "xsl": "http://www.w3.org/1999/XSL/Transform",
+    "at": "http://plone.org/archetypes",
+    }
+
+class AppMap:
+
+    def __init__(self):
+        
+        # Open the appmap file, make a tree, and process XIncludes
+        self.module_dir = os.path.dirname(os.path.abspath(__file__))
+        layoutsfn = os.path.join(self.module_dir, "etc/appmap.xml")
+        self.tree = etree.ElementTree(file=layoutsfn)
+        self.tree.xinclude()
+
+        # Make a themeprocessor to style all outgoing pages.  Note that the 
+        # .processor attribute comes from an lxml namespace binding, meaning it is 
+        # defined via a custom Python class defined below (class LayoutElement)
+        root = self.tree.getroot()
+        layout = root.xpath("dv:layouts/dv:layout", nsmap)[0]
+        self.themeprocessor = layout.processor
+
+
+    def publish(self, xmlstring):
+        """Given a string of XML, theme it"""
+        
+        # Stage 1 and 2, get an etree for the rendered resource
+        resource = etree.XML(xmlstring)
+        
+        # Stage 3, apply theme
+        response = str(self.themeprocessor(resource))
+
+        return response
+
+# The following are extensions based on lxml namespace extensions.  It 
+# adds Python behavior to XML nodes.
+
+class DVRuleBase(ElementBase):
+
+    def getThemeNode(self):
+        """Get a node in the theme doc"""
+
+        # Current node is a rule, get xpath from the @theme attr
+        themedoc = self.xpath("../../dv:theme", nsmap)[0][0]
+        xpath = self.get("theme")
+        try:
+            themenode = themedoc.xpath(xpath, nsmap)[0]
+        except IndexError:
+            msg = "Themedoc has no node at: %s" % xpath
+            print msg
+            themenode = None
+
+        return themenode
+
+
+class LayoutElement(ElementBase):
+
+    def processor(self):
+        """Make XSLT processor by changing theme based on rules"""
+
+        # Apply all the rules
+        for rule in self.xpath("./dv:rules/*", nsmap):
+            rule.apply()
+
+        # Merge applied rules into compilerdoc
+        compilerroot = self.xpath("../dv:compiler/xsl:stylesheet", nsmap)[0]
+        themeroot = self.xpath("dv:theme/html:html", nsmap)[0]
+        target = compilerroot.xpath("xsl:template[@match='/']", nsmap)[0]
+        target.append(themeroot)
+        
+        #print etree.tostring(compilerroot)
+
+        return etree.XSLT(compilerroot)
+    
+    processor = property(processor)
+        
+
+class RuleReplaceElement(DVRuleBase):
+
+    def apply(self):
+        # TODO: Someething here
+        themenode = self.getThemeNode()
+        if themenode is None:
+            return
+        del(themenode[:])
+        themenode.text = None
+        xslvalueof = etree.SubElement(themenode,
+                                      "{%s}value-of" % nsmap["xsl"])
+        xslvalueof.set("select", self.get("content"))
+
+
+class RuleCopyElement(DVRuleBase):
+
+    def apply(self):
+        themenode = self.getThemeNode()
+        if themenode is None:
+            return
+        del(themenode[:])
+        themenode.text = None
+        xslvalueof = etree.SubElement(themenode,
+                                      "{%s}apply-templates" % nsmap["xsl"])
+        xslvalueof.set("select", self.get("content"))
+
+
+class RuleAppendElement(DVRuleBase):
+
+    def apply(self):
+        themenode = self.getThemeNode()
+        if themenode is None:
+            return
+        xslvalueof = etree.SubElement(themenode,
+                                      "{%s}apply-templates" % nsmap["xsl"])
+        xslvalueof.set("select", self.get("content"))
+
+
+# lxml Namespace support
+namespace = Namespace(nsmap['dv'])
+namespace['layout'] = LayoutElement
+namespace['replace'] = RuleReplaceElement
+namespace['copy'] = RuleCopyElement
+namespace['append'] = RuleAppendElement
+    
+
+def testit(xmlstring):
+    
+    appmap = AppMap()
+    result = appmap.publish(xmlstring)
+    
+    return result
+
+def timeit(xmlstring):
+    appmap = AppMap()
+    start = time()
+    iters = 50
+    for i in range(iters):
+        result = appmap.publish(xmlstring)
+    print result[0:2000]
+    print "Average time:", (time() - start) / iters
+    
+def main():
+    xmlstring = open("content/localhello.html").read()
+    timeit(xmlstring)
+    #testit(path1)
+    
+if __name__ == "__main__":
+    result = main()
+    print result

Added: z3/deliverance/branches/namespaced/doc/NOTES.rst
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/doc/NOTES.rst	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,43 @@
+===============
+Random Notes
+===============
+
+This file collects random points to weave into other document docs.
+
+0) You can do runtime creation of themes from remote URLs.  This is a lot easier than 
+you'd think.  It could be possible to even build a reasonably smart, productive web 
+front end for finding the plug points on each side.  (About the only part that would 
+take some thinking is URL rewriting for stuff that keeps getting served by another 
+host, such as images and CSS.)
+
+1) The mod_python integration is done as a handler rather than a filter.  This is just 
+historical: In something else, am currently using the module to also resolve certain 
+URLs that are managed in an XML "map".
+
+2) For the XML "map" stuff, xml:id support is what makes it so fast.  However, this 
+imposes some limitations.  For example, you can't have slashes in xml:id values.
+
+3) Yeh, it doesn't have tests, other than the timeit function at the bottom 
+of deliverance.py.  I'm not yet much of a programmer.  I hope to fix this deficiency 
+during downtime in July.
+
+4) Neat point: Because of XInclude, the appmap XML document has everything it 
+needs, including the generated stuff, in a view-source friendly format.   Want to 
+see what's happening?  Just dump the XML document and look at it.
+
+5) The theme doesn't have to be well-formed XML.  The HTMLParser can handle garbage as 
+input and generate well-formed (though perhaps not valid) stuff on output.
+
+6) The append rule in etc/themerules.xml shows that you can easily copy page-specific 
+CSS, JS, etc. from the content document's <head> into the resulting <head>.
+
+7) Extensibility is provided through XML namespaces and lxml's namespace binding 
+support.  Want a new rule?  Just add it and bind a Python handler to it.
+
+8) The "compilation" step provides a nice opportunity to accomplish two goals:
+
+a. Make things simple.  Deliverance doesn't expose XSLT to users.  Other things 
+can be hidden as well.
+
+b. Optimize.  If there are calculations that are dynamic, but only calculated 
+once, they can be moved into this little pipeline.

Added: z3/deliverance/branches/namespaced/etc/appmap.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/etc/appmap.xml	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<appmap xmlns:xi="http://www.w3.org/2001/XInclude" xmlns="http://www.plone.org/deliverance">
+    <layouts>
+        <layout>
+            <theme>
+                <xi:include href="../themes/simple/sampletheme.xml"/>
+            </theme>
+            <xi:include href="themerules.xml"/>
+        </layout>
+        <compiler>
+            <xi:include href="../themecompiler.xsl"/>
+        </compiler>
+    </layouts>
+    <contentspace>
+        <content>
+            <xi:include href="themecontent.xml"/>
+        </content>
+        <generator>
+            <xi:include href="../renderer.xsl"/>
+        </generator>
+    </contentspace>
+</appmap>

Added: z3/deliverance/branches/namespaced/etc/themecontent.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/etc/themecontent.xml	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<content xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:at="http://plone.org/archetypes">
+    <at:collection xml:id="root" xmlns="http://plone.org/archetypes" title="Home">
+        <providers name="providers" xml:id="providers" title="Providers">
+            <provider name="providers/enfold" xml:id="providers.enfold" title="Enfold"/>
+            <provider name="providers/zea" xml:id="providers.zea" title="Zea Partners"/>
+        </providers>
+        <localfile name="localhello" xml:id="localhello" title="Local Hello File">
+            <xi:include href="../themes/simple/localhello.html"/>
+        </localfile>
+    </at:collection>
+</content>

Added: z3/deliverance/branches/namespaced/etc/themerules.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/etc/themerules.xml	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rules xmlns="http://www.plone.org/deliverance">
+    <replace theme="html:head/html:title" content="/html:html/html:head/html:title"/>
+    <replace theme="//html:h1[@id='pagetitle']" content="/html:html/html:head/html:title"/>
+    <copy theme="//html:div[@id='pagecontent']" content="html:html/html:body/*"/>
+    <append theme="html:head"
+        content="/html:html/html:head/html:link|/html:html/html:head/html:script"/>
+</rules>

Added: z3/deliverance/branches/namespaced/modpython.conf
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/modpython.conf	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,12 @@
+# This module can be pointed to from your main Apache 
+# configuration file to apply a theme to certain parts of your
+# URL space
+
+LoadModule python_module modules/mod_python.so
+
+<Directory /Users/paul/sandboxes/z3/deliverance/branches/namespaced>
+   AddHandler mod_python .py
+   PythonHandler modpython
+   PythonDebug On
+</Directory>
+

Added: z3/deliverance/branches/namespaced/modpython.py
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/modpython.py	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,25 @@
+"""
+Deliverance publisher for mod_python
+
+This module gets imported by mod_python during its startup.  Thus, the 
+appmap instance becomes a global, computed only once.  If you need to 
+recompute the theme, for example, restart the Apache.
+"""
+
+from mod_python import apache
+from deliverance import AppMap
+appmap = AppMap()
+
+def handler(req):
+    """Basic handler applying to all mime types it is registered for"""
+
+    # Get the path, strip off leading slash, and convert to a 
+    # dotted notation for xml:id compatibility
+    path_info = req.path_info[1:]
+    dotted_path = path_info.replace("/", ".")
+    
+    response = appmap.publish(dotted_path)
+    req.content_type = "text/html"
+    req.write(response)
+
+    return apache.OK

Added: z3/deliverance/branches/namespaced/renderer.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/renderer.xsl	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:trois="http://www.plone.org/trois" xmlns="http://www.w3.org/1999/xhtml"
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:at="http://plone.org/archetypes" exclude-result-prefixes="trois at html" version="1.0">
+    <xsl:output indent="yes"/>
+    <xsl:param name="pathinfo">localhello</xsl:param>
+    <xsl:param name="siteurl">/sandboxes/trois/trunk/deliverance/examples/plonenet.py</xsl:param>
+    <xsl:variable name="contentnode" select="id($pathinfo)"/>
+    <xsl:template match="/">
+        <html xmlns="http://www.w3.org/1999/xhtml">
+            <head>
+                <title>
+                    <xsl:value-of select="$contentnode/@title"/>
+                </title>
+            </head>
+            <body>
+                <div id="navtree">
+                    <xsl:apply-templates select="id('root')" mode="navtree"/>
+                </div>
+                <div id="pagecontent">
+                    <xsl:apply-templates select="$contentnode"/>
+
+                </div>
+
+            </body>
+        </html>
+    </xsl:template>
+    <xsl:template match="at:collection" mode="navtree">
+        <div
+            style="float:left; width: 10em; background-color: yellow; height: 10em; margin-right: 5em">
+            <h2 style="text-align: center">sitenav</h2>
+            <ul>
+                <xsl:for-each select=".//*[@name]">
+                    <li>
+                        <a href="{$siteurl}/{@name}">
+                            <xsl:value-of select="@title"/>
+                        </a>
+                    </li>
+                </xsl:for-each>
+            </ul>
+
+        </div>
+    </xsl:template>
+
+    <xsl:template match="at:providers">
+        <ul>
+            <li>Item one</li>
+            <xsl:for-each select="at:provider">
+                <li>
+                    <xsl:value-of select="@title"/>
+                </li>
+            </xsl:for-each>
+        </ul>
+    </xsl:template>
+    
+    <xsl:template match="at:provider">
+        <p>
+            <xsl:value-of select="@title"/>
+        </p>
+    </xsl:template>
+
+    <xsl:template match="at:localfile">
+        <xsl:copy-of select="html:html/html:body/*"/>
+    </xsl:template>
+    
+</xsl:stylesheet>

Added: z3/deliverance/branches/namespaced/themecompiler.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/themecompiler.xsl	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml"
+    exclude-result-prefixes="html" version="1.0">
+    <!-- Theme compiler.  Applied to the rule file to generate 
+        an XSLT that gets applied to content. -->
+    <xsl:output indent="yes" method="xml"/>
+    <xsl:template match="/">
+        <!-- The compiled theme gets shoved in here -->
+    </xsl:template>
+    <xsl:template match="node()|@*">
+        <xsl:copy>
+            <xsl:apply-templates select="node()|@*"/>
+        </xsl:copy>
+    </xsl:template>
+</xsl:stylesheet>

Added: z3/deliverance/branches/namespaced/themes/simple/sampletheme.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/themes/simple/sampletheme.xml	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <title>Theme Title</title>
+        <link rel="stylesheet" type="text/css" href="simpletheme.css"/>
+    </head>
+    <body>
+        <div id="agiheader">
+            <img src="http://www.foogle.biz/deliverance_the_movie/deliverance2_guitar.jpg"
+                alt="Banjos"/>
+            <a href="/sandboxes/trois/trunk/deliverance/examples/plonenet.py/providers/enfold"
+                >enfold</a> | <a
+                href="/sandboxes/trois/trunk/deliverance/examples/plonenet.py/providers/zea">zea</a>
+        </div>
+        <div id="pageframe">
+            <h1 id="pagetitle">Theme Title</h1>
+
+            <div id="pagecontent">This gets replaced because it is theme content.</div>
+
+        </div>
+    </body>
+</html>

Added: z3/deliverance/branches/namespaced/themes/simple/simpletheme.css
==============================================================================
--- (empty file)
+++ z3/deliverance/branches/namespaced/themes/simple/simpletheme.css	Wed Jul  5 20:50:26 2006
@@ -0,0 +1,26 @@
+
+body { 
+  font-size: 0.9em;
+  font-family: Helvetica;
+  margin: 0;
+}
+
+#agiheader {
+  height: 3.5em;
+  background-color: lightgray;
+  padding: 0.5em;
+}
+
+#pageframe { 
+  margin: 2em;
+}
+
+#agifooter {
+  	position: fixed;
+	bottom: 0;
+	left: 0;
+	height: 1.8em;
+	width: 100%;
+	background-color:yellow;
+	padding: 0.4em;
+}


More information about the z3-checkins mailing list