8a0e715d366444a5c8ceee6dea398965abcc6044
[xuriella.git] / doc / example.xml
blob8a0e715d366444a5c8ceee6dea398965abcc6044
1 <page title="Xuriella XSLT Example">
2   <p>Example using XSLT in a Hunchentoot handler to deliver an HTML page</p>
4   <h3>Overview</h3>
6   <p>
7     Suppose you're writing a web application (say,
8     using <a href="">Hunchentoot</a>), and you would like to show
9     directory contents.
10   </p>
11   <p>
12     We do that in two steps, strictly separating the programmer-written
13     Lisp code from the XSLT stylesheet that a web designer might want to
14     tweak afterwards:
15   </p>
16   <p>
17     <ul>
18       <li>
19         First we call CL:DIRECTORY, and build a small in-memory XML
20         document listing the files.
21       </li>
22       <li>
23         In the main step, the run that XML document through an XSL
24         stylesheet to generate HTML.
25       </li>
26     </ul>
27   </p>
29   <h3>Hunchentoot setup</h3>
30   <p>
31     The example requires hunchentoot and xuriella:
32   </p>
33   <pre style="background-color: #eeeeee; border: 1px solid #cccccc;">
34 (asdf:operate 'asdf:load-op :hunchentoot)
35 (asdf:operate 'asdf:load-op :xuriella)
36 </pre>
38   <p>
39     Let's start hunchentoot and register a handler for the example first:
40   </p>
41   <pre style="background-color: #eeeeee; border: 1px solid #cccccc;">
42 (push (tbnl:create-prefix-dispatcher "/show-directory" 'show-directory)
43       tbnl:*dispatch-table*)
44 (tbnl:start-server :port 4242)
45 </pre>
47   <h3>Utility functions</h3>
48   <p>
49     Since we might want to write many different handlers using
50     stylesheets, we factor
51     the APPLY-STYLESHEET call out into a convenient macro WITH-STYLESHEET.
52     Its body is expected to provide XML, which it will send through the
53     stylesheet and return the result as a string.
54   </p>
55   <p>
56     Note the use of WITH-XML-OUTPUT and STP:MAKE-BUILDER to build the
57     intermediate XML as an in-memory document using STP.
58   </p>
59   <p>
60     (In real-world code, we could optimize this a little by compiling the
61     stylesheet ahead of time using PARSE-STYLESHEET, and building a cache out
62     of stylesheet objects in a hash table somewhere.)
63   </p>
64   <pre style="background-color: #eeeeee; border: 1px solid #cccccc;">
65 (defmacro with-stylesheet ((stylesheet-pathname) &amp;body body)
66   `(invoke-with-stylesheet (lambda () ,@body) ,stylesheet-pathname))
68 (defun invoke-with-stylesheet (fn stylesheet-pathname)
69   (xuriella:apply-stylesheet (pathname stylesheet-pathname)
70                              (cxml:with-xml-output (stp:make-builder)
71                                (funcall fn))))
72 </pre>
74   <h3>Building the temporary XML</h3>
75   <p>
76     Now for the handler calling DIRECTORY.   We want our XML to look like
77     this:
78     <pre>
79     &lt;directory namestring="/home/jrhacker/">
80       &lt;file>hello-world.lisp&lt;/file>
81       &lt;file>mbox&lt;/file>
82       ...
83     &lt;/directory></pre>
84     which we can generate easily using WITH-ELEMENT and DOLIST:
85   </p>
86   <pre style="background-color: #eeeeee; border: 1px solid #cccccc;">
87 (defun show-directory ()
88   (<b>with-stylesheet</b> ("directory.xsl")
89     (<b>cxml:with-element "directory"</b>
90       (let ((directory (user-homedir-pathname)))
91         (cxml:attribute "namestring" (namestring directory))
92         (<b>dolist (file (directory (merge-pathnames "*.*" directory)))</b>
93           (<b>cxml:with-element "file"</b>
94             (cxml:text (enough-namestring file directory))))))))
95   </pre>
97   <h3>An XSL stylesheet as a template</h3>
98   <p>
99     Finally, the XSL stylesheet that turns this into HTML for us.  Note
100     the xsl:version on the root element, which marks the literal result
101     element used as a stylesheet.
102   </p>
103   <p>
104     Since &lt;html> is the root element, the stylesheet processor will
105     turn on its HTML output method automatically, and generate HTML 4
106     rather than XML.  (Powered by Closure HTML.)
107   </p>
108   <p>
109     To keep the example short and simple, our HTML is not very fancy.
110   </p>
111   <pre style="background-color: #eeeeee; border: 1px solid #cccccc;">
112 &lt;html xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
113       xsl:version="1.0">
114   &lt;head>
115     &lt;title>
116       &lt;xsl:value-of select="/directory/@namestring"/>
117     &lt;/title>
118   &lt;/head>
120   &lt;body>
121     &lt;h1>
122       Index of &lt;xsl:value-of select="/directory/@namestring"/>
123     &lt;/h1>
124     
125     &lt;ul>
126       &lt;xsl:for-each select="/directory/file">
127         &lt;li>
128           &lt;xsl:value-of select="."/>
129         &lt;/li>
130       &lt;/xsl:for-each>
131     &lt;/ul>
132   &lt;/body>
133 &lt;/html>
134 </pre>
136   <h3>Try it!</h3>
137   <p>
138     That's it.  If you open <tt>http://localhost:4242/show-directory</tt>
139     in a browser, you should see a listing of your home directory.
140   </p>
141 </page>