From e5c1bcbf175be0227438d19dae9f5b7c9f741a97 Mon Sep 17 00:00:00 2001
From: David Lichteblau Example using XSLT in a Hunchentoot handler to deliver an HTML page
+ Suppose you're writing a web application (say,
+ using Hunchentoot), and you would like to show
+ directory contents.
+
+ We do that in two steps, strictly separating the programmer-written
+ Lisp code from the XSLT stylesheet that a web designer might want to
+ tweak afterwards:
+
+ Overview
+
+
+
+
+ The example requires hunchentoot and xuriella: +
++(asdf:operate 'asdf:load-op :hunchentoot) +(asdf:operate 'asdf:load-op :xuriella) ++ +
+ Let's start hunchentoot and register a handler for the example first: +
++(push (tbnl:create-prefix-dispatcher "/show-directory" 'show-directory) + tbnl:*dispatch-table*) +(tbnl:start-server :port 4242) ++ +
+ Since we might want to write many different handlers using + stylesheets, we factor + the APPLY-STYLESHEET call out into a convenient macro WITH-STYLESHEET. + Its body is expected to provide XML, which it will send through the + stylesheet and return the result as a string. +
++ Note the use of WITH-XML-OUTPUT and STP:MAKE-BUILDER to build the + intermediate XML as an in-memory document using STP. +
++ (In real-world code, we could optimize this a little by compiling the + stylesheet ahead of time using PARSE-STYLESHEET, and building a cache out + of stylesheet objects in a hash table somewhere.) +
++(defmacro with-stylesheet ((stylesheet-pathname) &body body) + `(invoke-with-stylesheet (lambda () ,@body) ,stylesheet-pathname)) + +(defun invoke-with-stylesheet (fn stylesheet-pathname) + (xuriella:apply-stylesheet (pathname stylesheet-pathname) + (cxml:with-xml-output (stp:make-builder) + (funcall fn)))) ++ +
+ Now for the handler calling DIRECTORY. We want our XML to look like + this: +
+ <directory namestring="/home/jrhacker/"> + <file>hello-world.lisp</file> + <file>mbox</file> + ... + </directory>+ which we can generate easily using WITH-ELEMENT and DOLIST: + +
+(defun show-directory () + (with-stylesheet ("directory.xsl") + (cxml:with-element "directory" + (let ((directory (user-homedir-pathname))) + (cxml:attribute "namestring" (namestring directory)) + (dolist (file (directory (merge-pathnames "*.*" directory))) + (cxml:with-element "file" + (cxml:text (enough-namestring file directory)))))))) ++ +
+ Finally, the XSL stylesheet that turns this into HTML for us. Note + the xsl:version on the root element, which marks the literal result + element used as a stylesheet. +
++ Since <html> is the root element, the stylesheet processor will + turn on its HTML output method automatically, and generate HTML 4 + rather than XML. (Powered by Closure HTML.) +
++ To keep the example short and simple, our HTML is not very fancy. +
++<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xsl:version="1.0"> + <head> + <title> + <xsl:value-of select="/directory/@namestring"/> + </title> + </head> + + <body> + <h1> + Index of <xsl:value-of select="/directory/@namestring"/> + </h1> + + <ul> + <xsl:for-each select="/directory/file"> + <li> + <xsl:value-of select="."/> + </li> + </xsl:for-each> + </ul> + </body> +</html> ++ +
+ That's it. If you open http://localhost:4242/show-directory + in a browser, you should see a listing of your home directory. +
+ diff --git a/doc/index.xml b/doc/index.xml index 7a03f17..3f40492 100644 --- a/doc/index.xml +++ b/doc/index.xml @@ -28,8 +28,8 @@2007-xx-yy
+2009-04-04