[Repoze-checkins] r1399 - in repoze.lxmlgraph/trunk/docs: . step00 step01/myapp step02/myapp step03/myapp

Paul Everitt paul at agendaless.com
Sat Jul 19 09:17:35 EDT 2008


Author: Paul Everitt <paul at agendaless.com>
Date: Sat Jul 19 09:17:35 2008
New Revision: 1399

Log:
Fix up some NWO bugs.  Switch to using @name on the XML nodes, to correspond to __name__.  Change RST to use numbered lists.

Modified:
   repoze.lxmlgraph/trunk/docs/background.rst
   repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml
   repoze.lxmlgraph/trunk/docs/step01.rst
   repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml
   repoze.lxmlgraph/trunk/docs/step02.rst
   repoze.lxmlgraph/trunk/docs/step02/myapp/configure.zcml
   repoze.lxmlgraph/trunk/docs/step02/myapp/models.py
   repoze.lxmlgraph/trunk/docs/step02/myapp/samplemodel.xml
   repoze.lxmlgraph/trunk/docs/step03.rst
   repoze.lxmlgraph/trunk/docs/step03/myapp/configure.zcml
   repoze.lxmlgraph/trunk/docs/step03/myapp/models.py
   repoze.lxmlgraph/trunk/docs/step03/myapp/samplemodel.xml
   repoze.lxmlgraph/trunk/docs/step03/myapp/views.py
   repoze.lxmlgraph/trunk/docs/step03/myapp/xsltview.xsl

Modified: repoze.lxmlgraph/trunk/docs/background.rst
==============================================================================
--- repoze.lxmlgraph/trunk/docs/background.rst	(original)
+++ repoze.lxmlgraph/trunk/docs/background.rst	Sat Jul 19 09:17:35 2008
@@ -57,7 +57,7 @@
 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 ``@id`` attribute
+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
@@ -91,21 +91,22 @@
 This demo application has the potential to show some other interesting
 investigations:
 
-1) Authorization.  By hooking up support for an ``__acl__`` property,
-I can store ACL information on a single node, on an ancestor, on the
-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.
-
-2) 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.
-
-3) 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``.
+#. **Authorization**.  By hooking up support for an ``__acl__``
+   property, I can store ACL information on a single node, on an
+   ancestor, on the 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``.
 
 

Modified: repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml	(original)
+++ repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml	Sat Jul 19 09:17:35 2008
@@ -3,8 +3,8 @@
     <site>
         <title>My XMLGRAPH Website</title>
     </site>
-    <folder xml:id="n1" id="folder1">
-        <document xml:id="n11" id="doc1">
+    <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">
@@ -13,15 +13,15 @@
                 </div>
             </body>
         </document>
-        <document xml:id="n12" id="doc2">
+        <document xml:id="n12" name="doc2">
             <title>doc2 in folder1</title>
         </document>
     </folder>
-    <folder xml:id="n2" id="folder2">
-        <document xml:id="n21" id="doc1">
+    <folder xml:id="n2" name="folder2">
+        <document xml:id="n21" name="doc1">
             <title>doc1 in folder2</title>
         </document>
-        <document xml:id="n22" id="doc2">
+        <document xml:id="n22" name="doc2">
             <title>doc2 in folder2</title>
         </document>
     </folder>

Modified: repoze.lxmlgraph/trunk/docs/step01.rst
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step01.rst	(original)
+++ repoze.lxmlgraph/trunk/docs/step01.rst	Sat Jul 19 09:17:35 2008
@@ -61,18 +61,18 @@
    :linenos:
    :language: xml
 
-1) Lines 1-3 provide the root element and namespaces for the
-configuration language.  ``bfg`` is the namespace for
-``repoze.bfg``-specific configuration directives.
-
-2) Line 5 initializes those ``repoze.bfg``-specific configuration
-directives.
-
-3) 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 ``factory`` attribute points at a Python function that
-does all the work for this view.
+#. Lines 1-3 provide the root element 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``
@@ -86,15 +86,15 @@
 .. literalinclude:: step01/myapp/models.py
    :linenos:
 
-1) Lines 5-6 define the interface.
+#. Lines 5-6 define the interface.
 
-2) Lines 8-11 provide a class for that interface.
+#. Lines 8-11 provide a class for that interface.
 
-3) Lines 13-15 make a small tree of sample data (``/a`` and ``/b`` for
-URLs.)
+#. Lines 13-15 make a small tree of sample data (``/a`` and ``/b`` for
+   URLs.)
 
-4) Line 17 is a function that will be grabbed by the server when it
-wants to find the top of the model.
+#. 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``
@@ -116,16 +116,16 @@
 .. literalinclude:: step01/myapp/models.py
    :linenos:
 
-1) 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 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.
 
-2) Lines 4-7 generate a WebOb Response object and return it.
+#. Lines 4-7 generate a WebOb Response object and return it.
 
 
 Module ``run.py``
@@ -138,18 +138,18 @@
 .. literalinclude:: step01/run.py
    :linenos:
 
-1) Line 1 uses the web server from the Paste project.
+#. Line 1 uses the web server from the Paste project.
 
-2) Line 3 imports the big gun from ``repoze.bfg``.
+#. Line 3 imports the big gun from ``repoze.bfg``.
 
-3) Line 4 grabs the function that hands back the top of the
-application's model data.
+#. Line 4 grabs the function that hands back the top of the
+   application's model data.
 
-4) Line 5 imports the package that we want to "publish".
+#. Line 5 imports the package that we want to "publish".
 
-5) Line 7 loads the big gun with the data and the package.
+#. Line 7 loads the big gun with the data and the package.
 
-6) And finally, line 8 starts the web server on port 5432.
+#. And finally, line 8 starts the web server on port 5432.
 
 
 Running and Browsing the Application

Modified: repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml	(original)
+++ repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml	Sat Jul 19 09:17:35 2008
@@ -7,7 +7,7 @@
   <!-- the default view for a MyModel -->
   <bfg:view
      for=".models.IMyModel"
-     factory=".views.my_hello_view"
+     view=".views.my_hello_view"
      />
 
 </configure>

Modified: repoze.lxmlgraph/trunk/docs/step02.rst
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step02.rst	(original)
+++ repoze.lxmlgraph/trunk/docs/step02.rst	Sat Jul 19 09:17:35 2008
@@ -32,19 +32,20 @@
    :linenos:
    :language: xml
 
-1) Line 2 provides the root of the model as an XML ``<root>`` node.
-The element name doesn't have to be ``<root>``.
+#. Line 2 provides the root of the model as an XML ``<root>`` node.
+   The element name doesn't have to be ``<root>``.
 
-2) In lines 3-4, the root 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.
+#. In lines 3-4, the root 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 ``id`` attribute.
-Each hop in the URL tries to grab a child with an attribute matching
-the next hop.  Also, the value of the ``@id`` should be unique in its
-containing node.
+``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``
@@ -60,30 +61,30 @@
 .. literalinclude:: step02/myapp/models.py
    :linenos:
 
-1) Line 4 imports lxml.
+#. Line 4 imports lxml.
 
-2) 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.
-
-3) 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.
-
-4) ``repoze.bfg`` has a "protocol" where model data should have an
-``__name__`` attribute.  Lines 14-16 implement this by grabbing the
-``@id`` attribute of the current node.
-
-5) 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 ``@id`` matching the
-item id that's being traversed to.  If it finds it, return it.  If
-not, or if more than one is found, raise an error.
-
-6) 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.
+#. 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``
@@ -94,11 +95,11 @@
 .. literalinclude:: step02/myapp/views.py
    :linenos:
 
-1) Line 5 grabs the element name (tag name) of the ``context``, which
-is the current XML node that we're traversing through.
+#. Line 5 grabs the element name (tag name) of the ``context``, which
+   is the current XML node that we're traversing through.
 
-2) Line 6 uses the special property we defined in our custom Python
-class to get the ``__name__`` of the context.
+#. Line 6 uses the special property we defined in our custom Python
+   class to get the ``__name__`` of the context.
 
 
 Browsing the Model

Modified: repoze.lxmlgraph/trunk/docs/step02/myapp/configure.zcml
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step02/myapp/configure.zcml	(original)
+++ repoze.lxmlgraph/trunk/docs/step02/myapp/configure.zcml	Sat Jul 19 09:17:35 2008
@@ -1,13 +1,11 @@
 <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"
-     factory=".views.my_hello_view"
+     view=".views.my_hello_view"
      />
 
 </configure>

Modified: repoze.lxmlgraph/trunk/docs/step02/myapp/models.py
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step02/myapp/models.py	(original)
+++ repoze.lxmlgraph/trunk/docs/step02/myapp/models.py	Sat Jul 19 09:17:35 2008
@@ -13,15 +13,15 @@
 
     @property
     def __name__(self):
-        return self.xpath("@id")[0]
+        return self.xpath("@name")[0]
 
-    def __getitem__(self, item_id):
-        xp = "*[@id='%s']" % item_id
+    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' % item_id)
+            raise KeyError('No child found for %s' % child_name)
         elif len(matches) > 1:
-            raise KeyError('More than one child for %s' % item_id)
+            raise KeyError('More than one child for %s' % child_name)
         else:
             return matches[0]
 

Modified: repoze.lxmlgraph/trunk/docs/step02/myapp/samplemodel.xml
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step02/myapp/samplemodel.xml	(original)
+++ repoze.lxmlgraph/trunk/docs/step02/myapp/samplemodel.xml	Sat Jul 19 09:17:35 2008
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <root>
-    <document id="a"/>
-    <document id="b"/>
+    <document name="a"/>
+    <document name="b"/>
 </root>

Modified: repoze.lxmlgraph/trunk/docs/step03.rst
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step03.rst	(original)
+++ repoze.lxmlgraph/trunk/docs/step03.rst	Sat Jul 19 09:17:35 2008
@@ -22,7 +22,7 @@
 
   <bfg:view
      for=".models.IMyModel"
-     factory=".views.zpt_default_view"
+     view=".views.zpt_default_view"
      />
 
 Here we point to a function in ``myapp/views.py`` that looks like the
@@ -74,6 +74,9 @@
    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::
 
@@ -97,22 +100,76 @@
 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.

Modified: repoze.lxmlgraph/trunk/docs/step03/myapp/configure.zcml
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step03/myapp/configure.zcml	(original)
+++ repoze.lxmlgraph/trunk/docs/step03/myapp/configure.zcml	Sat Jul 19 09:17:35 2008
@@ -5,12 +5,12 @@
 
   <bfg:view
      for=".models.IMyModel"
-     factory=".views.zpt_default_view"
+     view=".views.zpt_default_view"
      />
 
   <bfg:view
      for=".models.IMyModel"
-     factory=".views.xslt_view"
+     view=".views.xslt_view"
      name="xsltview.html"
      />
 

Modified: repoze.lxmlgraph/trunk/docs/step03/myapp/models.py
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step03/myapp/models.py	(original)
+++ repoze.lxmlgraph/trunk/docs/step03/myapp/models.py	Sat Jul 19 09:17:35 2008
@@ -13,15 +13,15 @@
 
     @property
     def __name__(self):
-        return self.xpath("@id")[0]
+        return self.xpath("@name")[0]
 
-    def __getitem__(self, item_id):
-        xp = "*[@id='%s']" % item_id
+    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' % item_id)
+            raise KeyError('No child found for %s' % child_name)
         elif len(matches) > 1:
-            raise KeyError('More than one child for %s' % item_id)
+            raise KeyError('More than one child for %s' % child_name)
         else:
             return matches[0]
 

Modified: repoze.lxmlgraph/trunk/docs/step03/myapp/samplemodel.xml
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step03/myapp/samplemodel.xml	(original)
+++ repoze.lxmlgraph/trunk/docs/step03/myapp/samplemodel.xml	Sat Jul 19 09:17:35 2008
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <root>
-    <document id="a">xx</document>
-    <document id="b">yy</document>
+    <document name="a"/>
+    <document name="b"/>
 </root>

Modified: repoze.lxmlgraph/trunk/docs/step03/myapp/views.py
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step03/myapp/views.py	(original)
+++ repoze.lxmlgraph/trunk/docs/step03/myapp/views.py	Sat Jul 19 09:17:35 2008
@@ -1,9 +1,10 @@
-from repoze.bfg.template import render_template
-from repoze.bfg.template import render_transform
+from repoze.bfg.template import render_template_to_response
+from repoze.bfg.template import render_transform_to_response
 
 def zpt_default_view(context, request):
-    fn = "default.pt"
-    return render_template(fn, name=context.__name__, node=context)
+    return render_template_to_response("default.pt", 
+                                       name=context.__name__, 
+                                       node=context)
 
 def xslt_view(context, request):
-    return render_transform("xsltview.xsl", context)
+    return render_transform_to_response("xsltview.xsl", context)

Modified: repoze.lxmlgraph/trunk/docs/step03/myapp/xsltview.xsl
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step03/myapp/xsltview.xsl	(original)
+++ repoze.lxmlgraph/trunk/docs/step03/myapp/xsltview.xsl	Sat Jul 19 09:17:35 2008
@@ -4,7 +4,7 @@
         <html>
             <head/>
             <body>
-                <h1>My template is viewing item: <xsl:value-of select="@id"/></h1>
+                <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>


More information about the Repoze-checkins mailing list