[Repoze-checkins] r1446 - in repoze.bfg/trunk/docs: . tutorials tutorials/cluegun tutorials/lxmlgraph tutorials/lxmlgraph/step00 tutorials/lxmlgraph/step01 tutorials/lxmlgraph/step01/myapp tutorials/lxmlgraph/step02 tutorials/lxmlgraph/step02/myapp tutorials/lxmlgraph/step03 tutorials/lxmlgraph/step03/myapp tutorials/lxmlgraph/step04 tutorials/lxmlgraph/step04/myapp

Paul Everitt paul at agendaless.com
Thu Jul 24 13:14:16 EDT 2008


Author: Paul Everitt <paul at agendaless.com>
Date: Thu Jul 24 13:14:16 2008
New Revision: 1446

Log:
Add tutorial sections

Added:
   repoze.bfg/trunk/docs/tutorials/
   repoze.bfg/trunk/docs/tutorials/cluegun/
   repoze.bfg/trunk/docs/tutorials/cluegun/index.rst
   repoze.bfg/trunk/docs/tutorials/index.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/NOTES.txt
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/background.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/index.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/installation.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/oxygen.xpr
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step00/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step00/simplemodel.xml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/__init__.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/configure.zcml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/models.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/views.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/run.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/__init__.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/configure.zcml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/models.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/samplemodel.xml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/views.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/run.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/__init__.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/configure.zcml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/default.pt
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/models.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/samplemodel.xml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/views.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/xsltview.xsl
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/run.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04.rst
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/__init__.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/configure.zcml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/models.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/samplemodel.xml
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/views.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/xsltview.xsl
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/run.py
   repoze.bfg/trunk/docs/tutorials/lxmlgraph/step05.rst
Modified:
   repoze.bfg/trunk/docs/index.rst

Modified: repoze.bfg/trunk/docs/index.rst
==============================================================================
--- repoze.bfg/trunk/docs/index.rst	(original)
+++ repoze.bfg/trunk/docs/index.rst	Thu Jul 24 13:14:16 2008
@@ -21,14 +21,19 @@
    narr/models
    narr/security
 
-API documentation
------------------
+Tutorials
+----------
+
+Step-by-step sample applications that use ``repoze.bfg``.
+
+.. toctree::
+   :maxdepth: 2
+
+   tutorials/lxmlgraph/index.rst
 
-:mod:`repoze.bfg`
------------------
 
-The :mod:`repoze.bfg` package contains the code nececessary to create
-and run a web application.
+API documentation
+-----------------
 
 .. toctree::
    :maxdepth: 2

Added: repoze.bfg/trunk/docs/tutorials/cluegun/index.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/cluegun/index.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,21 @@
+======================================
+ Shared Clipboard with repoze.cluegun
+======================================
+
+repoze.cluegun is a "pastebin" application, showing how you can use
+the ``repoze.bfg`` framework for posting and managing paste sessions.
+
+In this tutorial, you'll see:
+
+  - Persistence
+
+  - Handling form data
+
+  - z3c.pt templating
+
+  - Security
+
+.. toctree::
+   :maxdepth: 2
+
+  

Added: repoze.bfg/trunk/docs/tutorials/index.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/index.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,9 @@
+==============================
+``repoze.bfg`` Tutorials
+==============================
+
+.. toctree::
+   :maxdepth: 2
+
+   lxmlgraph
+

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/NOTES.txt
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/NOTES.txt	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,6 @@
+
+To Do
+------------
+
+- Dream up a ZPT/XSLT theme engine
+

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/background.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/background.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,113 @@
+Background
+====================
+
+This demo application presumes that you have an interest in XML
+technologies and might want to leverage them for a fast-as-hell, but
+rich and dynamic, website.  In this demo application, we build up,
+bit-by-bit, the functionality.  Thus, you don't have to know squatola
+about XML to follow along.
+
+In fact, the real purpose of this demo app is to teach its author how
+to use the stack (repoze.bfg, Paster, eggs, etc.)
+
+In summary:
+
+  - Represent a hierarchical site as hierarchical XML
+
+  - Inject ``repoze.bfg`` semantics into elements using ``lxml``
+
+  - Support flexible-but-fast rendering with XSLT
+
+.. warning::
+
+  If you dislike XML and related technologies such as XPath and XSLT,
+  you'll thoroughly detest this sample application.  Just to be
+  stupendously clear, ``repoze.bfg`` is in no way dependent on XML.
+  On the other hand, ``repoze.bfg`` happens to make XML publishing
+  kind fun.
+
+What It Does
+-------------------
+
+Imagine you have a website that looks like this::
+
+  /
+    folder1/
+      doc1
+      doc2
+      image1
+    folder2/
+      doc2
+
+Meaning, a heterogenous, nested folder structure, just like your hard
+drive.  (Unless you're one of those folks that uses your Windows
+Desktop as a flat filing system.)  How might I get that information
+into a website?
+
+Using ``repoze.bfg``, of course.  More specifically, with an XML file
+that models that hierarchy:
+
+.. literalinclude:: step00/simplemodel.xml
+	:language: xml
+
+How It Works
+-------------------
+
+To coerce ``repoze.bfg`` into publishing this model, I just need to
+sprinkle in some Python behavior.  For example, ``repoze.bfg`` uses
+``__getitem__`` to traverse the model.  I need my XML data to support
+this method.  Moreover, I want some specific behavior: run an XPath
+express on the node to get the child with the ``@name`` attribute
+matching the URL hop.
+
+Fortunately ``lxml`` makes this easy.  I can inject my nodes with a
+class that I write, thus providing my own ``__getitem__`` behavior.
+
+That class can also assert that my XML nodes provide an interface.
+The interface then lets me glue back into the standard ``repoze.bfg``
+machinery, such as associating views and permissions into the model.
+
+Neato torpedo.  And stinking fast.
+
+Next up, I need to provide views for the elements in the model.  I
+could, for example, use ZPT and manipulate the XML data using Python
+expressions against the lxml API.  Or, I could use XSLT.
+
+For the latter, I could register a different XSLT for every "view" on
+every interface.  Or, I could write one big XSLT, and let its template
+matching machinery decide who to render in a certain context.
+
+And finally, I could pass in just a single node and render it, or pass
+in the entire tree with a parameter identifying the context node.
+
+In the course of this writeup, we'll build ``repoze.lxmlgraph``
+step-by-step, starting with no XML.  Each of those decisions will be
+analyzed an implemented.  At the end, you'll see both the resulting
+demo application, plus the thought process that went along with it.
+
+What It Might Do
+--------------------
+
+This demo application has the potential to show some other interesting
+investigations:
+
+#. **Authorization**.  By hooking up support for an ``__acl__``
+   property, I can store ACL information on a single node, on an
+   ancestor, on the ``<site>`` root, on the Python class, or any
+   combination thereof.  Additionally, I can wire up the
+   ``__parent__`` attribute as a property that makes an lxml
+   ``node.getparent()`` call.
+
+#. **Multiple views**.  Instead of just having a single default view
+   on a node, I can allow other view names, all pointing at the same
+   factory and XSLT.  I simple grab that name and pass it in as a
+   paramter to the XSLT, which will run a different rule for
+   rendering.
+
+#. **Forms**.  To edit data in the model, I need to render a form,
+   then handle post data on the way back in.  For the former, it's
+   *really* easy in XSLT to make a very powerful, flexible, and
+   extensisible form rendering system.  For the latter, I'll have to
+   learn more about POST handlers in ``repoze.bfg``.
+
+

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/index.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/index.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,21 @@
+Publishing XML with repoze.bfg
+==========================================
+
+``repoze.bfg`` is, well, fun.  It brings back the good old days of
+Bobo, but with the good new days of WSGI.  With ``repoze.bfg``,
+hierarchical websites are a cinch to develop.
+
+XML is also hierarchical.  ``repoze.lxmlgraph`` is a demo application
+for ``repoze.bfg`` that shows publishing a tree of XML as a
+hierarchical website, while leveraging the facilities the gun gives
+you.
+
+.. toctree::
+   :maxdepth: 2
+
+   background
+   installation
+   step01
+   step02
+   step03
+   step04

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/installation.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/installation.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,22 @@
+Installation
+=====================
+
+You can get the final form of the demo application, along with all the
+steps along the way, via the miracles of virtualenv, easy_install and Paster
+templates::
+
+  $ virtualenv --no-site-packages myapp
+  $ cd myapp
+  $ source bin/activate
+  $ easy_install repoze.lxmlgraph
+  $ paster create -t lxmlgraph_project
+
+Answer the questions, then run the demo:
+
+  cd <<projectname>>
+  python run.py
+
+At that point a URL such as ``http://localhost:5432/folder2/query1``
+should work.
+
+  
\ No newline at end of file

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/oxygen.xpr
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/oxygen.xpr	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,509 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+    <meta>
+        <filters directoryPatterns="" filePatterns=""
+            positiveFilePatterns="" showHiddenFiles="false"/>
+        <options>
+            <serialized>
+                <map>
+                    <entry>
+                        <String xml:space="preserve">scenario.associations</String>
+                        <scenarioAssociation-array>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">xsltview</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XML</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">step04/myapp/xsltview.xsl</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">debugui-entryviewer</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XML</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">../../../repoze.debug/trunk/repoze/debug/static/debugui-entryviewer.xsl</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF modified</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">../../../../playground/paul/psu2008/themes/Untitled5.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">docbook/docbook5.framework/DocBook 5/Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">../../../../../guidetoec2.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                        </scenarioAssociation-array>
+                    </entry>
+                    <entry>
+                        <String xml:space="preserve">scenarios</String>
+                        <scenario-array>
+                            <scenario>
+                                <field name="name">
+                                    <String xml:space="preserve">Execute DDXQuery</String>
+                                </field>
+                                <field name="baseURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="footerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="fOPMethod">
+                                    <null/>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <null/>
+                                </field>
+                                <field name="headerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <String xml:space="preserve">${currentFileURL}</String>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">DD_XQUERY</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <null/>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list/>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String xml:space="preserve">DataDirect</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </scenario>
+                            <scenario>
+                                <field name="name">
+                                    <String xml:space="preserve">Execute SQL</String>
+                                </field>
+                                <field name="baseURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="footerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="fOPMethod">
+                                    <null/>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <null/>
+                                </field>
+                                <field name="headerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <String xml:space="preserve">${currentFileURL}</String>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">SQL</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <null/>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list/>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String xml:space="preserve">JDBC</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </scenario>
+                            <scenario>
+                                <field name="name">
+                                    <String xml:space="preserve">Execute XQuery</String>
+                                </field>
+                                <field name="baseURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="footerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="fOPMethod">
+                                    <null/>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <null/>
+                                </field>
+                                <field name="headerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <String xml:space="preserve">${currentFileURL}</String>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XQUERY</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <null/>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list/>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String xml:space="preserve">Saxon9B XQuery</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </scenario>
+                            <scenario>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF modified</String>
+                                </field>
+                                <field name="baseURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="footerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="fOPMethod">
+                                    <String xml:space="preserve">pdf</String>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <String xml:space="preserve">Built-in (Apache FOP)</String>
+                                </field>
+                                <field name="headerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <String xml:space="preserve">${frameworks}/docbook/xsl/fo/docbook.xsl</String>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <String xml:space="preserve">${currentFileURL}</String>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <File xml:space="preserve">${cfd}/${cfn}.pdf</File>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list>
+                                    <transformationParameter>
+                                    <field name="name">
+                                    <String xml:space="preserve">draft.mode</String>
+                                    </field>
+                                    <field name="value">
+                                    <String xml:space="preserve">no</String>
+                                    </field>
+                                    </transformationParameter>
+                                    <transformationParameter>
+                                    <field name="name">
+                                    <String xml:space="preserve">fop.extensions</String>
+                                    </field>
+                                    <field name="value">
+                                    <String xml:space="preserve">0</String>
+                                    </field>
+                                    </transformationParameter>
+                                    <transformationParameter>
+                                    <field name="name">
+                                    <String xml:space="preserve">fop1.extensions</String>
+                                    </field>
+                                    <field name="value">
+                                    <String xml:space="preserve">1</String>
+                                    </field>
+                                    </transformationParameter>
+                                    <transformationParameter>
+                                    <field name="name">
+                                    <String xml:space="preserve">linenumbering.extension</String>
+                                    </field>
+                                    <field name="value">
+                                    <String xml:space="preserve">1</String>
+                                    </field>
+                                    </transformationParameter>
+                                    <transformationParameter>
+                                    <field name="name">
+                                    <String xml:space="preserve">paper.type</String>
+                                    </field>
+                                    <field name="value">
+                                    <String xml:space="preserve">A4</String>
+                                    </field>
+                                    </transformationParameter>
+                                    <transformationParameter>
+                                    <field name="name">
+                                    <String xml:space="preserve">use.extensions</String>
+                                    </field>
+                                    <field name="value">
+                                    <String xml:space="preserve">1</String>
+                                    </field>
+                                    </transformationParameter>
+                                    </list>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String xml:space="preserve">Saxon6.5.5</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </scenario>
+                            <scenario>
+                                <field name="name">
+                                    <String xml:space="preserve">xsltview</String>
+                                </field>
+                                <field name="baseURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="footerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="fOPMethod">
+                                    <String xml:space="preserve">pdf</String>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <String xml:space="preserve">Built-in (Apache FOP)</String>
+                                </field>
+                                <field name="headerURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <String xml:space="preserve">${currentFileURL}</String>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <String xml:space="preserve">file:/Users/paul/projects/repozesvn/repoze.lxmlgraph/trunk/docs/step04/myapp/samplemodel.xml</String>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XML</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <null/>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String xml:space="preserve"></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean xml:space="preserve">false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean xml:space="preserve">true</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list/>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String xml:space="preserve">Xsltproc</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </scenario>
+                        </scenario-array>
+                    </entry>
+                    <entry>
+                        <String xml:space="preserve">scenarios.load.from.project</String>
+                        <Boolean xml:space="preserve">true</Boolean>
+                    </entry>
+                </map>
+            </serialized>
+        </options>
+    </meta>
+    <projectTree name="oxygen.xpr">
+        <folder path="."/>
+        <folder path="../../../../../venvs/bfg/myapp-bak/"/>
+    </projectTree>
+</project>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step00/simplemodel.xml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step00/simplemodel.xml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<site>
+  <title>My XMLGRAPH Website</title>
+  <folder xml:id="n1" name="folder1">
+    <document xml:id="n11" name="doc1">
+      <title>doc1 in folder1</title>
+      <body>
+        <div xmlns="http://www.w3.org/1999/xhtml">
+          <p>Welcome to the site.  We have lots to say.</p>
+          <p>Or, <em>maybe</em> not.</p>
+        </div>
+      </body>
+    </document>
+    <document xml:id="n12" name="doc2">
+      <title>doc2 in folder1</title>
+    </document>
+  </folder>
+  <folder xml:id="n2" name="folder2">
+    <document xml:id="n21" name="doc1">
+      <title>doc1 in folder2</title>
+    </document>
+    <document xml:id="n22" name="doc2">
+      <title>doc2 in folder2</title>
+    </document>
+  </folder>
+</root>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,188 @@
+================================================
+Step 01: Non-XML Hello World for ``repoze.bfg``
+================================================
+
+Before we work on implementing an XML graph, we need a simple starting
+point for a basic ``repoze.bfg`` application.  In this step we'll do
+the least amount possible to run a ``repoze.bfg`` sample application.
+
+.. note::
+
+  All steps in this writeup presume that you have a virtualenv setup
+  as shown in the Installation step.  More specifically: *make sure
+  you are using that virtualenv's Python* !!
+
+Directory Layout
+====================
+
+Each step in this writeup has a subdirectory for the working
+application described in that step.  Thus, starting at this docs
+directory, we have::
+
+  docs/
+    step01/
+      myapp/
+        __init__.py
+      	configure.zcml
+      	models.py
+      	views.py
+      run.py
+    step02/
+    step03/
+
+Below we discuss each file in the ``step01``, then show how to run and
+use the demo application.
+
+
+Directory ``myapp``
+---------------------
+
+This directory contains the *package* to be published.  That's right,
+I said *package*.  ``repoze.bfg``, as we will see in a moment, uses
+Python packages as the unit of publishing.
+
+
+Module ``myapp/__init__.py``
+------------------------------
+
+This is (usually-empty) file that makes a directory into a Python
+"package."  For ``repoze.bfg`` this is particularly important
+
+
+Module ``myapp/configure.zcml``
+--------------------------------
+
+Unlike other frameworks, ``repoze.bfg`` doesn't try to hide
+configuration.  Instead, configuration using ZCML is the central
+wiring point.  At the same time, ZCML is used in a very basic way, to
+avoid confusion it can cause.
+
+.. literalinclude:: step01/myapp/configure.zcml
+   :linenos:
+   :language: xml
+
+#. Lines 1-3 provide the root node and namespaces for the
+   configuration language.  ``bfg`` is the namespace for
+   ``repoze.bfg``-specific configuration directives.
+
+#. Line 5 initializes those ``repoze.bfg``-specific configuration
+   directives.
+
+#. Lines 8-11 register a single view for model objects that support
+   the IMyModel interface.  In this case we made a default view, which
+   means going to ``/a`` triggers the default view of instance ``a``.
+   Finally, the ``view`` attribute points at a Python function that
+   does all the work for this view.
+
+
+Module ``myapp/models.py``
+-----------------------------
+
+In our sample app, the ``models.py`` module provides the model data.
+We create an interface ``IMyModel`` that gives us the "type system"
+for our data.  We then write a class ``MyModel`` that provides the
+behavior for instances of the ``IMyModel`` type.
+
+.. literalinclude:: step01/myapp/models.py
+   :linenos:
+
+#. Lines 5-6 define the interface.
+
+#. Lines 8-11 provide a class for that interface.
+
+#. Lines 13-15 make a small tree of sample data (``/a`` and ``/b`` for
+   URLs.)
+
+#. Line 17 is a function that will be grabbed by the server when it
+   wants to find the top of the model.
+
+
+Module ``myapp/views.py``
+---------------------------
+
+Much of the heavy liftin in a ``repoze.bfg`` application comes in the
+views.  These are the bridge between the content in the model, and the
+HTML given back to the browser.  Since ``repoze.bfg`` is very
+type-centric, URLs grab information of a certain type.  Once we have
+the information and its type, we can grab a view that is registered
+for that type.
+
+.. note::
+
+  This "Step 01" doesn't use a template.  The "view" we define is done
+  in Python, which generates the HTML.  Most applications will use
+  templates to generate markup.
+
+.. literalinclude:: step01/myapp/models.py
+   :linenos:
+
+#. Lines 3 provide the ``my_hello_view`` that was registered as the
+   view.  ``configure.zcml``, on Line 10, said that the default URL
+   for IMyModel content should run this ``my_hello_view`` function.
+
+   The function is handed two pieces of information: the ``context``
+   and the ``request``.  The ``context`` is the data at the current
+   hop in the URL.  (That data comes from the model.)  The request is
+   an instance of a WebOb request.
+
+#. Lines 4-7 generate a WebOb Response object and return it.
+
+
+Module ``run.py``
+---------------------
+
+We need a small Python module that sets everything, fires up a web
+server, and handles incoming requests.  Later we'll see how to use a
+Paste configuration file to do this work for us.
+
+.. literalinclude:: step01/run.py
+   :linenos:
+
+#. Line 1 uses the web server from the Paste project.
+
+#. Line 3 imports the big gun from ``repoze.bfg``.
+
+#. Line 4 grabs the function that hands back the top of the
+   application's model data.
+
+#. Line 5 imports the package that we want to "publish".
+
+#. Line 7 loads the big gun with the data and the package.
+
+#. And finally, line 8 starts the web server on port 5432.
+
+
+Running and Browsing the Application
+---------------------------------------
+
+We have our minimal application now in place.  We can run the
+application as follows::
+
+  cd docs/step01
+  python run.py
+
+.. note::
+
+  Just to say it AGAIN: make sure the Python you are using is the
+  Python from your virtual environment.  One way to ensure you always
+  get the right scripts is to do ``source bin/activate`` from the top
+  of your virtualenv.  This will modify your PATH to look first in the
+  virtual env.
+
+You should then see::
+
+  $ python ./run.py 
+  serving on 0.0.0.0:5432 view at http://127.0.0.1:5432
+
+If you connect in a web browser to ``http://localhost:5432/a`` you
+will see::
+
+  Hello from a @ /a
+
+This also works for ``http://localhost:5432/b``.  However, if you
+connect to ``http://localhost:5432/c`` you will get::
+
+  404 Not Found
+  The resource could not be found.
+
+  http://localhost:5432/c
\ No newline at end of file

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/__init__.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/__init__.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1 @@
+#

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/configure.zcml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/configure.zcml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,13 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+	   xmlns:bfg="http://namespaces.repoze.org/bfg">
+
+  <!-- this must be included for the view declarations to work -->
+  <include package="repoze.bfg" />
+
+  <!-- the default view for a MyModel -->
+  <bfg:view
+     for=".models.IMyModel"
+     view=".views.my_hello_view"
+     />
+
+</configure>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/models.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/models.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,18 @@
+from zope.interface import implements
+from zope.interface import Attribute
+from zope.interface import Interface
+
+class IMyModel(Interface):
+    __name__ = Attribute('Name of the model instance')
+
+class MyModel(dict):
+    implements(IMyModel)
+    def __init__(self, name):
+        self.__name__ = name
+
+root = MyModel('site')
+root['a'] = MyModel('a')
+root['b'] = MyModel('b')
+
+def get_root(environ):
+    return root

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/views.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/myapp/views.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,7 @@
+from webob import Response
+
+def my_hello_view(context, request):
+    response = Response('Hello from %s @ %s' % (
+            context.__name__, 
+            request.environ['PATH_INFO']))
+    return response

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/run.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step01/run.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,8 @@
+from paste import httpserver
+
+from repoze.bfg import make_app
+from myapp.models import get_root
+import myapp
+
+app = make_app(get_root, myapp)
+httpserver.serve(app, host='0.0.0.0', port='5432')

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,118 @@
+================================================
+Step 02: Hello World as XML
+================================================
+
+We now have a website with ``/a`` and ``/b`` URLs.  Each has a default
+view that returns a teensy weensy response.
+
+In this step we will do the exact some scope, but using an XML
+document as our model data.  We will leverage the same ``repoze.bfg``
+machinery:
+
+  - Model data with interfaces that define "types"
+
+  - ZCML configuration to provide type-specific views
+
+We do, however, need to do some things differently:
+
+  - Our model class needs to use lxml to inject itelf into the XML
+    nodes
+
+  - That model class needs to implement the "handshake"
+
+Let's look at what changed.
+
+File ``myapp/samplemodel.xml``
+--------------------------------
+
+Our hierarchy in Step 01 was very simple.  Mimicking it in XML is,
+thus, also very simple:
+
+.. literalinclude:: step02/myapp/samplemodel.xml
+   :linenos:
+   :language: xml
+
+#. Line 2 provides the root of the model as an XML ``<site>`` node.
+   The element name doesn't have to be ``<site>``.
+
+#. In lines 3-4, the ``<site>`` contains 2 top-level children: a and
+   b.  These are provided as an element name ``<document>``.  This,
+   also, is meaningfless as far as ``repoze.bfg`` is concerned.
+   However, this is where you compose th information model you are
+   publishing.
+
+The only special constraint is that a node that wants to be "found" by
+``repoze.bfg`` in during traversal *must* have an ``name`` attribute.
+(The use of ``@name`` corresponds to ``__name__`` in the
+``repoze.bfg`` handshake.)  Each hop in the URL tries to grab a child
+with an attribute matching the next hop.  Also, the value of the
+``@name`` should be unique in its containing node.
+
+
+Module ``myapp/models.py``
+------------------------------
+
+Here is the serious change: we have made an XML-aware model.  Or is it
+a model-aware XML document?  Such questions, harrumph.
+
+At a high level, we make write a class that "extends" lxml Element
+nodes, create an lxml parser, and register the custom class with the
+parser.
+
+.. literalinclude:: step02/myapp/models.py
+   :linenos:
+
+#. Line 4 imports lxml.
+
+#. Line 9 creates the custom class we are going to use to extend
+   etree.ElementBase.  The lxml website has great documentation on the
+   various ways to inject custom Python behavior into XML.
+
+#. Just as before, line 12 says that instances of this class support a
+   certain content type (interface.)  In our case, instances will be
+   XML nodes.
+
+#. ``repoze.bfg`` has a "protocol" where model data should have an
+   ``__name__`` attribute.  Lines 14-16 implement this by grabbing the
+   ``@name`` attribute of the current node.
+
+#. URL traversal in ``repoze.bfg`` works via the ``__getitem__``
+   protocol.  Thus, we need a method that implements this.  Lines
+   18-26 use XPath to look for a direct child that has an ``@name``
+   matching the item name that's being traversed to.  If it finds it,
+   return it.  If not, or if more than one is found, raise an error.
+
+#. As before, ``get_root`` is the function that is expected to return
+   the top of the model.  In lines 30-32 we do the lxml magic to get
+   the custom Python class registered.  We then load some XML and
+   return the top of the tree.
+
+
+Module `myapp/views.py``
+--------------------------
+
+We only made two changes here.
+
+.. literalinclude:: step02/myapp/views.py
+   :linenos:
+
+#. Line 5 grabs the element name (tag name) of the ``context``, which
+   is the current XML node that we're traversing through.
+
+#. Line 6 uses the special property we defined in our custom Python
+   class to get the ``__name__`` of the context.
+
+
+Browsing the Model
+------------------------
+
+We can use the same URLs from Step 01 to browser the model and see
+results::
+
+  http://localhost:5432/a
+  http://localhost:5432/b
+  http://localhost:5432/c (Not Found)
+
+In this case, each request grabs a node in the XML and uses it as the
+data for the view.  ``repoze.bfg`` doesn't really know that, unlike
+Step 01, we no longer have "real" Python data.
\ No newline at end of file

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/__init__.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/__init__.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1 @@
+#

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/configure.zcml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/configure.zcml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+	   xmlns:bfg="http://namespaces.repoze.org/bfg">
+
+  <include package="repoze.bfg" />
+
+  <bfg:view
+     for=".models.IMyModel"
+     view=".views.my_hello_view"
+     />
+
+</configure>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/models.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/models.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,41 @@
+from zope.interface import implements
+from zope.interface import Attribute
+from zope.interface import Interface
+from lxml import etree
+
+class IMyModel(Interface):
+    __name__ = Attribute('Name of the model instance')
+
+class BfgElement(etree.ElementBase):
+    """Handle access control and getitem behavior"""
+
+    implements(IMyModel)
+
+    @property
+    def __name__(self):
+        return self.xpath("@name")[0]
+
+    def __getitem__(self, child_name):
+        xp = "*[@name='%s']" % child_name
+        matches = self.xpath(xp)
+        if len(matches) == 0:
+            raise KeyError('No child found for %s' % child_name)
+        elif len(matches) > 1:
+            raise KeyError('More than one child for %s' % child_name)
+        else:
+            return matches[0]
+
+def get_root(environ):
+    # Setup the custom parser with our BfgElement behavior
+    parser_lookup = etree.ElementDefaultClassLookup(element=BfgElement)
+    parser = etree.XMLParser()
+    parser.set_element_class_lookup(parser_lookup)
+
+    # Now load the XML file
+    xmlstring = open("myapp/samplemodel.xml").read()
+    root = etree.XML(xmlstring, parser)
+
+    return root
+
+
+

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/samplemodel.xml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/samplemodel.xml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+    <document name="a"/>
+    <document name="b"/>
+</site>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/views.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/myapp/views.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,8 @@
+from webob import Response
+
+def my_hello_view(context, request):
+    response = Response('Hello to %s from %s @ %s' % (
+            context.tag, 
+            context.__name__, 
+            request.environ['PATH_INFO']))
+    return response

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/run.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step02/run.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,8 @@
+from paste import httpserver
+
+from repoze.bfg import make_app
+from myapp.models import get_root
+import myapp
+
+app = make_app(get_root, myapp)
+httpserver.serve(app, host='0.0.0.0', port='5432')

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,175 @@
+================================================
+Step 03: Basic Rendering With ZPT and XSLT
+================================================
+
+Our XML-based model is now usable.  However, we're using Python to
+generate the HTML, instead of a template.  In this step, we'll look at
+wiring up some templates, using both ZPT and XSLT.
+
+In a nutshell, this means:
+
+  - Slight changes to the ZCML
+
+  - View functions that assemble information and call the template
+
+ZPT Templates
+========================
+
+Let's start with a ZPT-based default view for the nodes in the XML.
+The ZCML for this would look like this:
+
+.. code-block:: xml
+
+  <bfg:view
+     for=".models.IMyModel"
+     view=".views.zpt_default_view"
+     />
+
+Here we point to a function in ``myapp/views.py`` that looks like the
+following:
+
+.. code-block:: python
+   :linenos:
+
+   from repoze.bfg.template import render_template_to_response
+   def zpt_default_view(context, request):
+      fn = "default.pt"
+      return render_template_to_response(fn, name=context.__name__, node=context)
+
+This function is relatively simple:
+
+#. Line 1 imports a ``repoze.bfg`` function that renders ZPT
+   templates.  ``repoze.bfg`` uses the ``z3c.pt`` ZPT engine.
+
+#. Line 2, like our other view functions, gets passed a ``context``
+   (the current hop in the URL) and WebOb ``request`` object.
+
+#. Line 3 points at the filename of the ZPT.
+
+#. Line 4 calls the ``render_template_to_response`` function, passing in the
+   filename for the ZPT and two top-level variables that can be used
+   in the ZPT.  The first is the name of the current URL hop
+   (context).  The second is the XML node object for that hop
+   (context).
+
+In Step 01 and 02, we returned a WebOb Response object that we
+created.  ``render_template_to_response`` makes a Response itself.
+
+Here's what the ZPT looks like:
+
+.. literalinclude:: step03/myapp/default.pt
+   :linenos:
+   :language: xml
+
+Look, a template!  Life is better with templating:
+
+#. Lines 1-2 make an ``<html>`` node with a namespace for TAL.
+
+#. Line 5 inserts the value of the ``name`` that we passed into
+   ``render_template_to_response``.
+
+#. Line 6 sure looks interesting.  It uses the ``node`` that we passed
+   in via ``render_template_to_response``.  Since ``z3c.pt`` uses
+   Python as its expession language, we can put anything Python-legal
+   between the braces.  And since ``node`` is an lxml Element object,
+   we just ask for its ``.tag``, like regular Python lxml code.
+
+Viewing the ZPT
+------------------
+
+With all of that in place, going to ``http://localhost:5432/a`` now
+generates, via the ZPT, the following::
+
+  My template is viewing item: a
+
+  The node has a tag name of: document.
+
+
+XSLT Templates
+====================
+
+So that's the ZPT way of rendering HTML for an XML document.  How
+might XSLT look?
+
+.. note::
+
+  For the following, we'll switch back to showing the complete module
+  code, rather than snippets.  You can then follow along by looking at
+  the files in ``docs/step03/myapp``.
+
+File ``myapp/configure.zcml``
+--------------------------------
+
+The ZCML statement for the XSLT template looks almost exactly the same
+as the ZPT template:
+
+.. literalinclude:: step03/myapp/configure.zcml
+   :linenos:
+   :language: xml
+
+#. Lines 10-14 wire up a new view, in addition to the default view.
+
+#. Line 13 provides the difference: ``name="xsltview.html"`` means
+   that all our URLs now can have ``/xsltview.xml`` appended to them.
+
+In the ZCML, there is no distinction between a ZPT view and an XSLT
+view.  The difference is only in the function that is pointed to by
+the ``view=`` attribute.
+
+
+Module ``myapp/views.py``
+--------------------------------
+
+The ZCML says that our XSLT view (``xsltview.html`` on the URL) comes
+from the ``myapp.views.xslt_view`` function:
+
+.. literalinclude:: step03/myapp/views.py
+   :linenos:
+
+#. Line 9 starts the Python function which serves as the view for this
+   template.  The function has the same signature as the
+   ``zpt_default_view`` function we defined for the ZPT template's
+   view.
+
+#. Line 10 implements the difference.  We call
+   ``render_transform_to_response`` instead of
+   ``render_template_to_response``.  This tells ``repoze.bfg`` to make
+   an XSLT processor for this template, instead of a ZPT.  The second
+   argument passes in ``context`` to the XSLT transform.  ``context```
+   is an instance of an Element node.  Namely, a node from the XML
+   document that corresponds to the current hop in the URL.
+
+
+File ``myapp/xsltview.xsl``
+--------------------------------
+
+How different does the XSLT itself look?  At this stage, not too different:
+
+.. literalinclude:: step03/myapp/xsltview.xsl
+   :linenos:
+   :language: xml
+
+#. Lines 1 and 2 are typical XSLT setup.
+
+#. Line 3 defines a rule to match on the node that is passed in.  In
+   our case, a ``<document>`` node.
+
+#. Line 7 inserts the value of the ``@id`` attribute from the
+   "current" node at that point in the rule.  We're sitting on the
+   ``<document>`` node (thanks to line 3).  Thus, ``<xsl:value of
+   select="@id"/>`` inserts ``a`` or ``b``, depending on which
+   document we are sitting on.
+
+#. Line 8 shows the element name of the current node.
+
+
+Viewing the XSLT
+--------------------
+
+With this in place, runnning the application provides a URL such as
+``http://localhost:5432/a/xsltview.html``.  Going to that URL should
+show::
+
+  My template is viewing item: a
+
+  The node has a name of: document.

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/__init__.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/__init__.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1 @@
+#

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/configure.zcml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/configure.zcml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,17 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+	   xmlns:bfg="http://namespaces.repoze.org/bfg">
+
+  <include package="repoze.bfg" />
+
+  <bfg:view
+     for=".models.IMyModel"
+     view=".views.zpt_default_view"
+     />
+
+  <bfg:view
+     for=".models.IMyModel"
+     view=".views.xslt_view"
+     name="xsltview.html"
+     />
+
+</configure>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/default.pt
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/default.pt	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,8 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <head></head>
+  <body>
+    <h1>My template is viewing item: ${name}</h1>
+    <p>The node has a tag name of: ${node.tag}.</p>
+  </body>
+</html>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/models.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/models.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,41 @@
+from zope.interface import implements
+from zope.interface import Attribute
+from zope.interface import Interface
+from lxml import etree
+
+class IMyModel(Interface):
+    __name__ = Attribute('Name of the model instance')
+
+class BfgElement(etree.ElementBase):
+    """Handle access control and getitem behavior"""
+
+    implements(IMyModel)
+
+    @property
+    def __name__(self):
+        return self.xpath("@name")[0]
+
+    def __getitem__(self, child_name):
+        xp = "*[@name='%s']" % child_name
+        matches = self.xpath(xp)
+        if len(matches) == 0:
+            raise KeyError('No child found for %s' % child_name)
+        elif len(matches) > 1:
+            raise KeyError('More than one child for %s' % child_name)
+        else:
+            return matches[0]
+
+def get_root(environ):
+    # Setup the custom parser with our BfgElement behavior
+    parser_lookup = etree.ElementDefaultClassLookup(element=BfgElement)
+    parser = etree.XMLParser()
+    parser.set_element_class_lookup(parser_lookup)
+
+    # Now load the XML file
+    xmlstring = open("myapp/samplemodel.xml").read()
+    root = etree.XML(xmlstring, parser)
+
+    return root
+
+
+

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/samplemodel.xml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/samplemodel.xml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+    <document name="a"/>
+    <document name="b"/>
+</site>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/views.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/views.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,10 @@
+from repoze.bfg.template import render_template_to_response
+from repoze.bfg.template import render_transform_to_response
+
+def zpt_default_view(context, request):
+    return render_template_to_response("default.pt", 
+                                       name=context.__name__, 
+                                       node=context)
+
+def xslt_view(context, request):
+    return render_transform_to_response("xsltview.xsl", context)

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/xsltview.xsl
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/myapp/xsltview.xsl	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+    <xsl:template match="/document">
+        <html>
+            <head/>
+            <body>
+                <h1>My template is viewing item: <xsl:value-of select="@name"/></h1>
+                <p>The node has a name of: <xsl:value-of select="name()"/>.</p>
+            </body>
+        </html>
+    </xsl:template>
+</xsl:stylesheet>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/run.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step03/run.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,8 @@
+from paste import httpserver
+
+from repoze.bfg import make_app
+from myapp.models import get_root
+import myapp
+
+app = make_app(get_root, myapp)
+httpserver.serve(app, host='0.0.0.0', port='5432')

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,98 @@
+================================================
+Step 04: Hierarchical Rendering With XSLT
+================================================
+
+Now that we have basic templating for our XML graph in place, let's
+start doing some fun stuff with it.  As we walk through use cases and
+build out patterns for implementing them, we'll get to leverage some
+features available in XML processors.  For better or worse. [wink]
+
+In this step we take a look at the following:
+
+- Build a nested, folder-like website
+
+- Render the HTML common to all pages, then render the part specific
+  to a certain page
+
+- Show contents of a folder when sitting on a folder, and content of a
+  document when sitting on a document
+
+
+Pre-Flight Cleanup
+====================
+
+In the last example, we had a default template that used ZPT.  We're
+shifting the rest of the steps over to XSLT.  Thus, our
+``myapp/configure.zcml`` is now simpler:
+
+.. literalinclude:: step04/myapp/configure.zcml
+   :linenos:
+   :language: xml
+
+We also remove the ZPT view function from ``views.py``, as we'll see
+in a moment.
+
+Design Change: Trees and Context IDs
+========================================
+
+In ``repoze.bfg``, the ``context`` variable that is passed into our
+view function equates to the Python object that was grabbed on the
+current hop in the URL.  For ``repoze.lxmlgraph``, that "context"
+object is a node in the XML document, found by traversing node
+children.
+
+For the XSLT in Step 03, we passed in the context node.  From the
+XSLT's perpective, the universe started at the context node.  It could
+only see information in that node and the children beneath it.
+
+If we could see the entire tree, however, we could put the other
+information to use: showing the name of the site in a header, listing
+the breadcrumbs to reach the document, and other portal-style boxes.
+
+To enable this, we need the following:
+
+#. A way to pass in the entire XML document tree.
+
+#. A way to uniquely point at the item in the XML that we are
+   currently sitting on, with the fastest performance possible.
+
+We will thus make the following changes in our approach:
+
+#. The XML document will support an ``xml:id`` attribute on each node
+   that has a ``name`` attribute.  The ``xml:id`` uniquely identifies
+   the resource within the document.  Moreover, it leverages built-in
+   support for high-speed lookups in XPath.
+
+#. We change the view function to pass in the root of the tree,
+   instead of the context node.
+
+#. We also pass in, via an XSLT parameter, the ``xml:id`` of the
+   context node.
+
+#. The XSLT will start at the top of the tree, generate the site-wide
+   look and feel, then render the context node.
+
+That's the big picture.  Each of these changes will be explained in
+detail below.
+
+
+File ``myapp/samplemodel.xml``
+================================
+
+The XML document with the information for our website has quite a
+number of changes:
+
+.. literalinclude:: step04/myapp/samplemodel.xml
+   :linenos:
+   :language: xml
+
+#. Line 3 shows that our ``<site>`` now gets a ``<title>``.
+
+#. On Line 4 we make an index document at the root that contains a
+   document-wide unique value for its ``@xml:id``.
+
+#. In lines 5-11, our ``<document>`` gets some extra information: a
+   ``<title>``, plus some HTML-namespaced markup content inside a
+   ``<body>``.
+
+#. 

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/__init__.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/__init__.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1 @@
+#

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/configure.zcml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/configure.zcml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+	   xmlns:bfg="http://namespaces.repoze.org/bfg">
+
+  <include package="repoze.bfg" />
+
+  <bfg:view
+     for=".models.IMyModel"
+     view=".views.xslt_view"
+     />
+
+</configure>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/models.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/models.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,41 @@
+from zope.interface import implements
+from zope.interface import Attribute
+from zope.interface import Interface
+from lxml import etree
+
+class IMyModel(Interface):
+    __name__ = Attribute('Name of the model instance')
+
+class BfgElement(etree.ElementBase):
+    """Handle access control and getitem behavior"""
+
+    implements(IMyModel)
+
+    @property
+    def __name__(self):
+        return self.xpath("@name")[0]
+
+    def __getitem__(self, child_name):
+        xp = "*[@name='%s']" % child_name
+        matches = self.xpath(xp)
+        if len(matches) == 0:
+            raise KeyError('No child found for %s' % child_name)
+        elif len(matches) > 1:
+            raise KeyError('More than one child for %s' % child_name)
+        else:
+            return matches[0]
+
+def get_root(environ):
+    # Setup the custom parser with our BfgElement behavior
+    parser_lookup = etree.ElementDefaultClassLookup(element=BfgElement)
+    parser = etree.XMLParser()
+    parser.set_element_class_lookup(parser_lookup)
+
+    # Now load the XML file
+    xmlstring = open("myapp/samplemodel.xml").read()
+    root = etree.XML(xmlstring, parser)
+
+    return root
+
+
+

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/samplemodel.xml
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/samplemodel.xml	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+    <title>My XMLGRAPH Website</title>
+    <document xml:id="index" name="index.html">
+        <title>Site Home Page</title>
+        <body>
+            <div xmlns="http://www.w3.org/1999/xhtml">
+                <p>Welcome to the site. We have lots to say.</p>
+                <p>Or, <em>maybe</em> not.</p>
+            </div>
+        </body>
+    </document>
+    <folder xml:id="n1" name="folder1">
+        <title>Folder One</title>
+        <document xml:id="n11" name="doc1">
+            <title>doc1 in folder1</title>
+            <body>
+                <div xmlns="http://www.w3.org/1999/xhtml">
+                    <p>I am in an HTML <code>div</code> so I can do <strong>LOTS</strong> of
+                        formatting.</p>
+                </div>
+            </body>
+        </document>
+        <document xml:id="n12" name="doc2">
+            <title>doc2 in folder1</title>
+            <body>
+                <div xmlns="http://www.w3.org/1999/xhtml">
+                    <p>Keep this on one line.</p>
+                </div>
+            </body>
+        </document>
+    </folder>
+    <folder xml:id="n2" name="folder2">
+        <title>The Second Folder</title>
+        <document xml:id="n21" name="doc1">
+            <title>doc1 in folder2</title>
+            <body>
+                <div xmlns="http://www.w3.org/1999/xhtml">
+                    <p>This is a special folder. It's folder 2!</p>
+                </div>
+            </body>
+        </document>
+    </folder>
+</site>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/views.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/views.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,13 @@
+from repoze.bfg.template import render_transform_to_response
+
+# Some constants
+XML_NAMESPACE='http://www.w3.org/XML/1998/namespace'
+XML_PREFIX= '{%s}' % XML_NAMESPACE
+
+def xslt_view(context, request):
+    # Grab the root of the tree, which should be a <site>
+    site = context.getroottree().getroot()
+    # Jot down which node we're sitting on as the <context>
+    contextid = "'%s'" % context.get(XML_PREFIX+'id')
+    return render_transform_to_response("xsltview.xsl", site, 
+                                        contextid=contextid)

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/xsltview.xsl
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/myapp/xsltview.xsl	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+    <xsl:param name="contextid">n1</xsl:param>
+    <xsl:variable name="contextnode" select="id($contextid)"/>
+    <xsl:template match="/">
+        <html>
+            <head>
+                <title>
+                    <xsl:value-of select="$contextnode/title"/>
+                </title>
+            </head>
+            <body>
+                <h2>
+                    <xsl:value-of select="$contextnode/title"/>
+                </h2>
+                <xsl:apply-templates select="$contextnode"/>
+                <table border="1" cellpadding="6" cellspacing="0">
+                    <tr>
+                        <th>Type</th>
+                        <th>@xml:id</th>
+                        <th>@name</th>
+                        <th>Parent Type</th>
+                        <th>Parent @name</th>
+                    </tr>
+                    <tr>
+                        <td>
+                            <xsl:value-of select="name($contextnode)"/>
+                        </td>
+                        <td>
+                            <xsl:value-of select="$contextnode/@xml:id"/>
+                        </td>
+                        <td>
+                            <xsl:value-of select="$contextnode/@name"/>
+                        </td>
+                        <td>
+                            <xsl:value-of select="name($contextnode/..)"/>
+                        </td>
+                        <td>
+                            <xsl:value-of select="$contextnode/../@name"/>
+                        </td>
+                    </tr>
+                </table>
+            </body>
+        </html>
+    </xsl:template>
+    <xsl:template match="folder">
+        <p>
+            <em>Folders are special, they contain things.</em>
+        </p>
+        <xsl:if test="*[@xml:id]">
+            <h2>Folder Contents</h2>
+            <ul>
+                <xsl:for-each select="*[@xml:id]">
+                    <li>
+                        <a href="{../@name}/{@name}">
+                            <xsl:value-of select="title"/>
+                        </a>
+                    </li>
+                </xsl:for-each>
+            </ul>
+        </xsl:if>
+    </xsl:template>
+    <xsl:template match="document">
+        <p>
+            <em>Documents contain text.</em>
+        </p>
+        <xsl:copy-of select="body/*"/>
+    </xsl:template>
+</xsl:stylesheet>

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/run.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step04/run.py	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,8 @@
+from paste import httpserver
+
+from repoze.bfg import make_app
+from myapp.models import get_root
+import myapp
+
+app = make_app(get_root, myapp)
+httpserver.serve(app, host='0.0.0.0', port='5432')

Added: repoze.bfg/trunk/docs/tutorials/lxmlgraph/step05.rst
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/docs/tutorials/lxmlgraph/step05.rst	Thu Jul 24 13:14:16 2008
@@ -0,0 +1,12 @@
+================================================
+Step 05: Advanced Templating
+================================================
+
+
+- multiple "views" wired to the same function and template
+
+- breadcrumbs, sidebars
+
+- <query> support
+
+- type-based support for <document>, <folder>, <query>, <site>
\ No newline at end of file


More information about the Repoze-checkins mailing list