[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