[z3-checkins] r55528 - in z3/deliverance/sandboxes/paul/dvng: . var

paul at codespeak.net paul at codespeak.net
Tue Jun 3 21:01:24 CEST 2008


Author: paul
Date: Tue Jun  3 21:01:20 2008
New Revision: 55528

Added:
   z3/deliverance/sandboxes/paul/dvng/
   z3/deliverance/sandboxes/paul/dvng/content3.html
   z3/deliverance/sandboxes/paul/dvng/dvngcompiler.py
   z3/deliverance/sandboxes/paul/dvng/mycustomizations.xsl
   z3/deliverance/sandboxes/paul/dvng/rules.rng
   z3/deliverance/sandboxes/paul/dvng/theme.html
   z3/deliverance/sandboxes/paul/dvng/theme2.html
   z3/deliverance/sandboxes/paul/dvng/themeset.xml
   z3/deliverance/sandboxes/paul/dvng/var/
Log:
Making a directory just for the dvng software, instead of the writeup

Added: z3/deliverance/sandboxes/paul/dvng/content3.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/content3.html	Tue Jun  3 21:01:20 2008
@@ -0,0 +1,24 @@
+<html>
+    <head>
+        <title>Red Balloons for Neanderthals</title>
+        <meta name="dv.section" content="DVNG Articles"/>
+        <meta name="dcmi.type" content="Gallery Page"/>
+        <meta name="dcmi.author" content="Grok Smasher"/>
+        <meta name="dcmi.modified" content="2007/02/21"/>
+    </head>
+    <body>
+        <ul id="related">
+            <li><a href="item1">Item One</a></li>
+            <li><a href="item2">Item Two</a></li>
+        </ul>
+        <ul id="breadcrumbs">
+            <li><a href="/">Home</a></li>
+            <li><a href="/articles">Articles</a></li>
+            <li>Red Balloons for Neanderthals</li>
+        </ul>
+        <div id="content">
+            <p>The article text <em>goes here</em>.</p>
+            <p>More content here.</p>
+        </div>
+    </body>
+</html>

Added: z3/deliverance/sandboxes/paul/dvng/dvngcompiler.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/dvngcompiler.py	Tue Jun  3 21:01:20 2008
@@ -0,0 +1,259 @@
+"""
+Compile a Deliverance themeset into a compiled themeset.
+
+"""
+
+from lxml import etree
+import os
+import sys
+import lxml.html
+
+# Constants
+DV_NAMESPACE = "http://openplans.org/deliverance"
+DV = "{%s}" % DV_NAMESPACE
+XSL_NAMESPACE = "http://www.w3.org/1999/XSL/Transform"
+XSL = "{%s}" % XSL_NAMESPACE
+NSMAP = {"dv": DV_NAMESPACE, "xsl": XSL_NAMESPACE}
+
+
+def dump(node, fn):
+    """Convenience function for quick saving to var directory """
+    
+    fullfn = os.path.join("var", fn)
+    f = open(fullfn, "w")
+    f.write(tostring(node))
+    f.close()
+    return
+
+
+def tostring(node):
+    """Convenience function for quick and pretty dumping"""
+
+    return etree.tostring(node, pretty_print=True)
+
+
+def get_tag(node):
+    """Convenience function to get tagname without namespace"""
+
+    return node.tag.split("}")[1]
+
+
+class DVNG2:
+
+    # heredir is set to the directory above step01-04
+    moduledir = os.path.dirname(os.path.abspath(__file__))
+    heredir = os.path.dirname(moduledir)[1:]
+
+    def __init__(self, themesetfn):
+        # Some paths and filenames
+        self.themesetfn = os.path.join(self.moduledir, themesetfn)
+        self.themes = []
+        self.themeset = etree.ElementTree(file=self.themesetfn)
+
+        # The .xsl file that serves as boilerplate for the final
+        stubfn = os.path.join(self.moduledir, "stub.xsl")
+        self.xslt = etree.ElementTree(file=stubfn).getroot()
+
+    def makeThemes(self):
+        """For each theme and page type, make a new Theme"""
+		
+        # We support page types by considering each of them 
+        # as a distinct theme with a cumulative match condition.
+        # Thus, our XPath matches first on pagetypes and then 
+        # on regular themes.
+        pt = self.themeset.xpath("dv:theme/dv:pagetype", namespaces=NSMAP)
+        t = self.themeset.xpath("dv:theme", namespaces=NSMAP)
+
+        i = 0
+        for ptt in pt + t:
+            i = i + 1
+            pttid = get_tag(ptt) + "-" + str(i)
+            theme = Theme(ptt, pttid)
+
+            # Find places in the theme html that need rules inserted
+            # and do so
+            theme.insertRules()
+            theme.makeXSLNode()
+            self.themes.append(theme)
+
+        return
+
+    def assembleStylesheet(self):
+        """Concatenate all the themes into an xsl:stylesheet"""
+
+        
+        params = {}
+        xsltemplate = self.xslt.xpath("xsl:template[@match='/']", 
+                                      namespaces=NSMAP)[0]
+        xslchoose = etree.SubElement(xsltemplate, XSL + "choose")
+        for theme in self.themes:
+            # Append the node, then each param
+            xslchoose.append(theme.xslwhen)
+            for param in theme.xslparams.keys():
+                params[param] = True
+
+        # Now generate the param nodes
+        for param in params.keys():
+            node = etree.Element(XSL + "param", name=param)
+            self.xslt.insert(0, node)
+
+        # If there is a /themeset/@custom, use it for custom rules
+        # that need to come in at a higher precedence.  Thus, 
+        # append them to the end.
+        custom = self.themeset.getroot().get("custom", None)
+        if custom is not None:
+            customfn = os.path.join(self.moduledir, custom)
+            customrules = etree.ElementTree(file=customfn)
+            for rule in customrules.xpath("/*/*"):
+                self.xslt.insert(0, rule)
+
+
+    def debug(self):
+        """Dump the list of themes and the compiled themeset"""
+        
+        for theme in self.themes:
+            print "----------\nTheme:", theme.pttid, "at", theme.href
+            print tostring(theme.htmlroot)
+            dump(theme.htmlroot, theme.pttid + "-html.xml")
+            dump(theme.xslwhen, theme.pttid + "-xsl.xml")
+
+        # Now dump the final, assembled XSLT to disk
+        dump(self.xslt, "dvfinalstage.xsl")
+
+    def asString(self):
+        """Serialize the xslt as the string representation"""
+
+        return tostring(self.xslt)
+
+
+class Theme:
+	
+    def __init__(self, ptt, pttid):
+        """Given a <pagetype> or a <theme>, make a theme"""
+
+        self.ptt = ptt
+        self.pttid = pttid
+
+        # We are currently sitting on a <pagetype> or a 
+        # <theme>.  The latter has the @href.  Thus, 
+        # make an XPath that walks up from the current node
+        # until it finds the @href.
+        self.href = ptt.xpath("ancestor-or-self::*/@href")[0]
+
+        # Load the HTML doc and make a backup copy
+        self.orightmldoc = lxml.html.parse(self.href)
+        self.htmlroot = lxml.html.parse(self.href).getroot()
+
+        # Place to hold <xsl:param> nodes that will go at the
+        # top
+        self.xslparams = {}
+
+    def _getNodes(self, xp):
+        """Convenience function for getting a node by XPath"""
+
+        return self.ptt.xpath(xp, namespaces=NSMAP)
+
+    def insertRules(self):
+        """Find insertion points for rules in the html"""
+
+        rules = self.ptt.xpath("dv:rules", namespaces=NSMAP)[0]
+
+        for rulenode in rules.xpath("*"):
+            targets = self.htmlroot.xpath(rulenode.get("theme"))
+            if not len(targets):
+                # Skip over if nothing in the theme matches
+                continue
+            ruletype = get_tag(rulenode)
+            parent = targets[0].getparent()
+            cxp = rulenode.get("content")
+            makerule = getattr(self, "_rule" + ruletype)
+            makerule(rulenode, parent, targets, cxp)
+
+    def _rulereplace(self, rulenode, parent, targets, cxp):
+
+        newnode = etree.Element(XSL + "apply-templates", select=cxp)
+		
+        if len(targets) > 1:
+            # Remove all targets, append xslt to parent
+            [parent.remove(i) for i in targets]
+            parent.append(newnode)
+            # XXX We're not actually getting in here as len() 
+            # doesn't do as expected
+        else:
+            parent.replace(targets[0], newnode)
+
+    def matchHandler(self, matchnode):
+        """Given <match> child, return string used in xsl:template"""
+
+        matchtype = get_tag(matchnode)
+        if matchtype == "content":
+            return matchnode.text
+        elif matchtype == "req":
+            pk = matchnode.get("key")
+            pv = matchnode.text
+            # Update the dict that will later drive creation 
+            # of /xsl:stylesheet/xsl:param nodes
+            self.xslparams["req." + pk] = True
+
+            # Make the string that will appear in the xsl:template
+            result = "$req.%s='%s'" % (pk, pv)
+            return result
+
+
+    def makeXSLNode(self):
+        """Set the OR'd string of match conditions for this theme"""
+
+        # Make compiler input document by wrapping each theme in
+        # an <xsl:template match="match conditions"
+
+
+        # If we are on a <pagetype>, we need the conditions for 
+        # both the pagetype/match and the theme/match.  We do this
+        # in two parts, because <pagetype>s need the two sets of
+        # conditions AND'd together.
+        mh = self.matchHandler
+        ptmatches = [mh(m) for m in self._getNodes("dv:match/*")]
+        tmatches = [mh(m) for m in self._getNodes("../dv:match/*")]
+	
+	# Handle cases where there are pagetype/match AND theme/match,
+        # just one, or just the other
+        if ptmatches and tmatches:
+            # Make an xsl:template that ANDs both match conditions
+            # for a <pagetype>
+            matchon = "html[%s]" % "(%s) and (%s)" % (
+                " or ".join(ptmatches), 
+                " or ".join(tmatches))
+        elif ptmatches:
+            # This is for a <pagetemplate> inside the last 
+            # them used when no other themes match
+            matchon = "html[%s]" % " or ".join(ptmatches)
+        elif tmatches:
+            # This is for a theme with either no <pagetype>
+            # or none that match
+            matchon = "html[%s]" % " or ".join(tmatches)
+        else:
+            # Handle the case where we are the last, default theme
+            # that should <xsl:template match="html"> for anything
+            matchon = "html"
+
+        # Now make the actual <xsl:when> node
+        xslnode = XSL + "when"
+        self.xslwhen = etree.Element(xslnode, test=matchon)
+        self.xslwhen.append(self.htmlroot)
+
+
+				
+def main():
+    themesetfn = sys.argv[1]
+    dvng = DVNG2(themesetfn)
+    dvng.makeThemes()
+    dvng.assembleStylesheet()
+
+    #dvng.debug()
+
+    result = dvng.asString()
+    return result
+	
+if __name__ == "__main__":
+    result = main()
+    print result

Added: z3/deliverance/sandboxes/paul/dvng/mycustomizations.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/mycustomizations.xsl	Tue Jun  3 21:01:20 2008
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:template match="/">
+    <div>I overroad everything!</div>
+  </xsl:template>
+</xsl:stylesheet>

Added: z3/deliverance/sandboxes/paul/dvng/rules.rng
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/rules.rng	Tue Jun  3 21:01:20 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/theme.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/theme.html	Tue Jun  3 21:01:20 2008
@@ -0,0 +1,11 @@
+<html>
+    <head>
+        <title>Theme Page Title</title>
+    </head>
+    <body>
+        <h1 id="pageheading">Theme Page Heading</h1>
+        <div id="pagecontent">
+            <p>Some sample theme content.</p>
+        </div>
+    </body>
+</html>
\ No newline at end of file

Added: z3/deliverance/sandboxes/paul/dvng/theme2.html
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/theme2.html	Tue Jun  3 21:01:20 2008
@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>Second Theme Page Title</title>
+    </head>
+    <body>
+        <table border="0" height="300" cellpadding="20">
+            <tr>
+                <td width="200" bgcolor="gray" valign="top">
+                    <h2 align="center">Navigation</h2>
+                </td>
+                <td valign="top">
+                    <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/themeset.xml
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvng/themeset.xml	Tue Jun  3 21:01:20 2008
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<themeset xmlns="http://openplans.org/deliverance" custom="mycustomizations.xsl">
+  <theme href="theme2.html">
+    <pagetype>
+      <match>
+        <content>/html</content>
+      </match>
+      <rules>
+        <replace theme="//td/h1[@id='pageheading']" content="/html/head/title"/>
+        <replace theme="//div[@id='pagecontent']" content="/html/body/div[@id='content']"/>
+      </rules>
+    </pagetype>
+    <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="theme.html">
+    <rules>
+      <replace theme="//div[@id='pagecontent']" content="/html/body/div[@id='content']"/>
+    </rules>
+  </theme>
+</themeset>


More information about the z3-checkins mailing list