From ba9b0e647bff1bf0c437ab204ddf11783ed698f8 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 1 May 2009 10:26:57 +0000 Subject: Merge "c-free" branch to trunk. --- docs/tutorials/lxmlgraph/step04.rst | 250 ------------------------------------ 1 file changed, 250 deletions(-) delete mode 100644 docs/tutorials/lxmlgraph/step04.rst (limited to 'docs/tutorials/lxmlgraph/step04.rst') diff --git a/docs/tutorials/lxmlgraph/step04.rst b/docs/tutorials/lxmlgraph/step04.rst deleted file mode 100644 index f96a0712f..000000000 --- a/docs/tutorials/lxmlgraph/step04.rst +++ /dev/null @@ -1,250 +0,0 @@ -================================================ -Step 4: 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 -``configure.zcml`` can now be madesimpler. Change your -``configure.zcml`` to lok like so: - -.. literalinclude:: step04/myapp/configure.zcml - :linenos: - :language: xml - -We'll also remove the ``zpt_view`` function from ``views.py``, as -we'll see in a moment. - -Design Change: Trees and Context IDs -======================================== - -In :mod:`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 ``lxmlgraph``, that "context" object is a -node in the XML document, found by traversing node children. - -For the XSLT in Step 3, 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. - -``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 ```` now gets a ````. - -#. 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>``. - -#. Lines 13-32 show a nested XML hierarchy. A ``<folder>`` gets an - ``@name``, making the folder itself published as a possible URL. - It also gets an ``@xml:id``, allowing it to be uniquely addressed - within the entire document. The ``<folder>`` gets a ``<title>`` - child node, but then gets two more ``__getitem__``-enabled child - nodes of type ``<document>``. ("Enabled", as in, has a ``@name`` - attribute.) - -Thus the major changes: - -- The root contains ``<folder>`` nodes which contain ``<document>`` - nodes. - -- The root could contain documents too, and the folder could contain - sub-folders. There's nothing special about the arrangement. - -- The only thing special is the presence of ``@name`` attributes, - which allow ``__getitem__`` (via XPath) to traverse to that child. - -- As we'll see in a second, the ``@xml:id`` allows jumping through the - hierarchy directly to a node. - -- Finally, for UI-framework-ish purposes, having a child ``<title>`` - allows us to show in a browser what we're looking at. - -The ``models.py`` hasn't changed, so let's move to the small changes -in the ``views.py``. - -``views.py`` -============ - -As noted above, we removed the ZPT views, and thus ``views.py`` is -shorter, and focused only on a function that provides an XSLT -template. Although there aren't many lines in that function, there -are some concepts to explain: - -.. literalinclude:: step04/myapp/views.py - :linenos: - -#. We are going to be using a feature from XML called ``xml:id``, - which we explained above in the ``samplemodel.xml`` section. In - lines 4 and 5, we make constants that point to the namespace - needed. - -#. As the comment says, line 9 grabs the "root" node of the site. - Inside this function, we are traversing, node-by-node, through a - hierarchy. Thus our context node is an lxml Element object, which - supports a method to grab the tree (and thus root) in which the - context sits. - -#. Next, to support the XSLT approach we show next, we want to let the - XSLT know the ``xml:id`` that we are sitting on. Since we are - passing it in as an XSLT paramter, we need some special handling: - - - The *value* of the parameter is the ``@xml:id`` of the node we are - sitting on. - - - Per lxml's needs, that value needs to be quoted. Thus, the value - of ``contextid`` will be something like ``"'n1'"`` - -#. Finally, on line 12, we call the XSLT processor, passing in keyword - arguments that become XSLT parameters. Unlike before, the node we - pass in is the top of the tree, rather than the current (context) - node. - -In summary, we render the XSLT by handing it the root node of the -tree, plus a flag that says which node we are currently sitting on. - -``xsltview.xsl`` -================= - -The XSLT template gets the most substantive changes, as we both have -to support this root-and-contextid idea, as well as some features that -put this to use: - -- Having a common look-and-feel across all pages, along with "rules" - that handle each content type - -- Show the context's ``<title>`` in the same place - -- Show some general information about the node - -The following XSLT accomplishes these features: - -.. literalinclude:: step04/myapp/xsltview.xsl - :linenos: - :language: xml - -#. Line 3 accepts the ``@xml:id`` passed in as a parameter of the XSLT - transformation. This can differ between requests, as different - nodes are traversed. - -#. Line 4 jumps directly to the tree node that has that ``@xml:id`` by - using XPath's ``id()`` function. This is a high-speed lookup, - similar to ``document.getElementById()`` in JavaScript. We then - assign the node to a global XSLT variable, to avoid paying that - price again. - -#. Line 5 gets into XSLT's rule-oriented mumbo-jumbo. This template - rule says: "Match on the root of the tree that was passed in, then - do some work." Think of this as a CSS rule that matches on ``body - {}``. - -#. Lines 7-11 output HTML for the document and ``<head>``. - -#. Line 9 (and line 14) inserts the value of the context node's - ``<title>`` using ``<xsl:value-of>``. - -#. Line 16 does some XSLT mumbo jumbo. It says "Find a rule that - handles the context node, which might be a ``<folder>`` or might be - a ``<document>``." Control is then passed to an ``<xsl:template>`` - that meets the conditions. Once that rule is finished, control - returns to line 17. - -#. Lines 17-42 then format some basic information about the context - node. The HTML generated for this, however, appears *after* the - type-specific handler in the resulting HTML. - -#. Line 46 is an ``<xsl:template>`` rule that handles ``<folder>`` - nodes. It only gets control when something else hands control to it. - - In this case, the rule makes a paragraph then lists the contents of - the folder. - -#. Line 50 checks to see if the folder contains any "publishable" - content. We wouldn't want a heading to appear saying "Folder - Contents" with empty space under it. - -#. Line 53 then iterates over all the child nodes which have an - ``@xml:id``. - -#. Lines 55-57 make an ``<li>`` with an ``<a>`` for each item in the - folder. Inside the ``<xsl:for-each``, the "current" node is the - current item in the iteration. The ``@href`` uses what XSLT calls - "attribute value template" (curly braces) to let the XSLT processor - operate inside an attribute. - -#. Line 63 handles ``<document>`` nodes when handed control. - -#. Line 67 recursively copies the nodes in the ``<document>`` content. - -To recap, this XSLT handles any node passed in, and generates a UI -that can handle the global styling, the navigational elements, and the -content for the current traversal hop. - -Conclusion -===================== - -Though not very much code, this is the basis for a useful amount of -features. A hierarchical website with templating that can handle -global styling and navigation, as well as type-driven templating, all -at reasonable (albeit in-memory) performance. - - -- cgit v1.2.3