You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by fleur diana dragan <fl...@obscure.org> on 2000/09/18 19:40:36 UTC

hoping for additional cocoon functionality

Hi,

I've been playing with Cocoon1 for a few days, specifically to see if I
can use Cocoon to do something specific so I don't have to write the
whole damn app myself for work.

Specifically, I need to be able to do XSL transforms on information that
comes from the request (i.e. headers, cgi variables).  The formdata
stuff appears to already be there via <xsl:param>, which is great.

As a proof-of-concept, I wrote a Producer that takes the DOM tree of the
requested file and adds a <request> element.  The xml file has a
<?cocoon-process type="xslt"?> directive.  It works nicely.  The
attached patch file is my implementation.

This is obviously the wrong way to do it.  (I disabled caching since the
<request> object may change, which is so completely wrong, it makes me
queasy, but hey, proof-of-concept, right?)

Anyway, if I could get comments on the idea and how best to implement
it, that would be great.  I'm thinking that making the request info
available via <xsl:param> elements would be best, but I haven't actually
looked at the code that implements it to be sure.  There's also probably
a big caching issue.  Again, since I haven't looked at the <xsl:param>
code, I don't know how it's handled.

Also, if this has been discussed (and maybe discarded) before, Somebody
tell me approximately when so I can go to the archives and read it!  :-)



thanks,
fleur
-- 
Fleur [Diana] Dragan / fleur@obscure.org -- It's my name.  Really.



need to add to cocoon.properties:
producer.type.request = org.apache.cocoon.producer.ProducerFromRequest

and invoke as:
[...]samples/request_producer/poem.xml?producer=request



===File ~/src/request_producer_patch========================
diff -Naur --exclude=CVS xml-cocoon-pure/samples/request_producer/poem.xml xml-cocoon/samples/request_producer/poem.xml
--- xml-cocoon-pure/samples/request_producer/poem.xml	Wed Dec 31 19:00:00 1969
+++ xml-cocoon/samples/request_producer/poem.xml	Mon Sep 18 11:29:51 2000
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="poem.xsl" type="text/xsl"?>
+<?cocoon-process type="xslt"?>
+<poems title="Dynamic Poems">
+
+  <description>
+    <paragraph>
+    This XML file has several poems in it.  These poems are in 
+    different languages.  Depending on what your browser sends in 
+    its "accept-language" header, one or more of these poems may 
+    show up for you based on the XSL transformation the XSL 
+    stylesheet for this file does.
+    </paragraph>
+    <paragraph>
+    Currently, this file contains poems in the following languages:
+    en-US, en-GB, it
+    </paragraph>
+    <paragraph>
+    To view any of these poems, you will likely have to add to the 
+    languages your browser accepts via the browser preferences.
+    </paragraph>
+  </description>
+
+  <poem title="FOG" author="Carl Sandburg" language="en-US">
+    <stanza>
+      <line>THE fog comes</line>
+      <line>on little cat feet.</line>
+    </stanza>
+
+    <stanza>
+      <line>It sits looking</line>
+      <line>over harbor and city</line>
+      <line>on silent haunches</line>
+      <line>and then moves on.</line>
+    </stanza>
+  </poem>
+
+  <poem title="La mia mamma, matta matta" language="it">
+    <stanza>
+      <line>La mia mamma, matta matta</line>
+      <line>M'ha pigiato nella pignatta.</line>
+      <line>Mia sorella, bella bella</line>
+      <line>M'ha posato nel cestello.</line>
+      <line>Il mio papĂ , quatton quattoni</line>
+      <line>M'ha pappato in un boccone.</line>
+      <line>Per l'amor di San Martino</line>
+      <line>Son diventato un bel uccellino:</line>
+      <line>Cip, cip, cip!</line>
+    </stanza>
+  </poem>
+
+  <poem title="A Thought" author="A. A. Milne" language="en-GB">
+    <stanza>
+      <line>If I were John, and John were Me,</line>
+      <line>Then he'd be six, and I'd be three.</line>
+      <line>If John were me, and I were John,</line>
+      <line>I shouldn't have these trousers on.</line>
+    </stanza>
+  </poem>
+
+</poems>
diff -Naur --exclude=CVS xml-cocoon-pure/samples/request_producer/poem.xsl xml-cocoon/samples/request_producer/poem.xsl
--- xml-cocoon-pure/samples/request_producer/poem.xsl	Wed Dec 31 19:00:00 1969
+++ xml-cocoon/samples/request_producer/poem.xsl	Fri Sep 15 14:01:01 2000
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:variable name="accepted_languages">
+    <xsl:value-of select="//request/headers/header[@name='accept-language']" />
+  </xsl:variable>
+
+  <xsl:template match="poems">
+   <html>
+    <head>
+     <title>
+      <xsl:value-of select="@title"/>
+     </title>
+    </head>
+    <body bgcolor="#ffffff">
+     <h1><xsl:value-of select="@title"/></h1>
+     <xsl:apply-templates select="description"/>
+     <p>
+        The languages your browser says you accept: 
+        <xsl:value-of select="$accepted_languages" />
+     </p>
+     <hr></hr>
+     <xsl:apply-templates select="poem"/>
+    </body>
+   </html>
+  </xsl:template>
+
+  <xsl:template match="description">
+    <xsl:apply-templates />
+  </xsl:template>
+
+  <xsl:template match="paragraph">
+    <p><xsl:value-of select="." /></p>
+  </xsl:template>
+
+  <xsl:template match="poem">
+    <xsl:if test="contains($accepted_languages, @language)">
+      <p>
+      <font size="+3">
+        <xsl:value-of select="@title" />
+      </font>
+      by 
+      <font size="+1">
+        <xsl:value-of select="@author" />
+      </font>
+      <xsl:apply-templates />
+      </p>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="stanza">
+    <p>
+      <xsl:apply-templates />
+    </p>
+  </xsl:template>
+
+  <xsl:template match="line">
+    <xsl:value-of select="." /><br></br>
+  </xsl:template>
+
+  <xsl:template match="request">
+    <h2>And now, some request information...</h2>
+    <xsl:apply-templates />
+  </xsl:template>
+
+  <xsl:template match="headers">
+    <table border="1">
+      <tr><th colspan="2">headers</th></tr>
+      <xsl:apply-templates />
+    </table>
+  </xsl:template>
+
+  <xsl:template match="header">
+    <tr>
+      <th align="right"><xsl:value-of select="@name" /></th>
+      <td><xsl:value-of select="." /></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="cgi_variables">
+  </xsl:template>
+
+  <xsl:template match="cookies">
+  </xsl:template>
+
+  <xsl:template match="formdata">
+    <table border="1">
+      <tr><th colspan="3">form data</th></tr>
+      <xsl:apply-templates />
+    </table>
+  </xsl:template>
+
+  <xsl:template match="pair">
+    <tr>
+      <th><xsl:value-of select="name" /></th>
+      <td><xsl:value-of select="value" /></td>
+      <td><xsl:value-of select="@source" /></td>
+    </tr>
+  </xsl:template>
+
+</xsl:stylesheet>
+
diff -Naur --exclude=CVS xml-cocoon-pure/src/org/apache/cocoon/producer/ProducerFromRequest.java xml-cocoon/src/org/apache/cocoon/producer/ProducerFromRequest.java
--- xml-cocoon-pure/src/org/apache/cocoon/producer/ProducerFromRequest.java	Wed Dec 31 19:00:00 1969
+++ xml-cocoon/src/org/apache/cocoon/producer/ProducerFromRequest.java	Fri Sep 15 22:45:40 2000
@@ -0,0 +1,291 @@
+package org.apache.cocoon.producer;
+
+
+import java.io.File;
+import java.io.Reader;
+import java.io.IOException;
+
+import java.net.*;
+import java.util.*;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.cocoon.*;
+import org.apache.cocoon.framework.*;
+
+/**
+ * This class implements the producer interface in order to produce a document
+ * based on its tranlated path.
+ * 
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @version $Revision: 1.9 $ $Date: 2000/05/06 11:13:53 $
+ */
+
+public class ProducerFromRequest extends AbstractProducer implements Status {
+
+  //    private Monitor monitor = new Monitor(10);
+
+    public Document getDocument(HttpServletRequest request) throws Exception {
+        String   file = null;
+				Document doc  = null;
+
+
+        file = Utils.getBasename(request, this.context);
+        //        this.monitor.watch(Utils.encode(request), new File(file));
+
+				doc = parser.parse(new InputSource(file));
+				addXMLRequestToDocument(request, doc);
+
+				return doc;
+    }    
+
+
+    public Reader getStream(HttpServletRequest request) throws Exception {
+        throw new Exception("this method should never be called!");
+    }
+
+
+    /**
+		 * Since the XML document that is produced from this is the 
+		 * file from the web server directory with the addition of 
+		 * some extra elements representing the request, there is no 
+		 * path for this document available.
+		 *
+		 * @param request   the HttpServletRequest object to generate 
+		 *                  the extra elements from
+		 *
+		 * @return          the empty string, since, according to the 
+		 *                  interface, we're not supposed to return null
+		 */
+    public String getPath(HttpServletRequest request) { return ""; }
+
+    
+    public boolean hasChanged(Object context) {
+        return true;
+    }
+    
+    public String getStatus() {
+        return "Producer from local file plus XML request info";
+    }
+
+
+    /**
+     * This method takes a HttpServletRequest object and a Document 
+		 * object and adds some XML conforming to teh following DTD:
+     *<pre>
+     <!ELEMENT request (url, cookie*, accept*, authdata*, postdata?)>
+     <!ELEMENT url (host, port?, path, queryargs*)>
+     <!ELEMENT postdata (content-type, content)>
+     <!ELEMENT method>
+     *
+     <!ELEMENT cookies (cookie+)>
+     <!ELEMENT cookie (name, value?)>
+     *</pre>
+     *
+     * @param req   the HttpSrevletRequest object to get the data from
+		 * @param doc   the Document object to add to
+     */
+    private void addXMLRequestToDocument(HttpServletRequest req, 
+																				 Document doc) throws IOException {
+        int             i        = 0;
+				Attr            tmpAttr  = null;
+        String          tmp      = null;
+        String[]        tmpA     = null;
+        Cookie[]        cookies  = null;
+				Element         rootElt = null;
+				Element         elt = null;
+				Element         tmpElt = null;
+				Element         nameElt = null;
+				Element         valElt = null;
+        Hashtable       h        = null;
+        Enumeration     enum     = null;
+
+
+
+
+				/* create the root element for the DOM tree we'll insert */
+				rootElt = doc.createElementNS("http://whatever", "request");
+        doc.getDocumentElement().appendChild(rootElt);
+
+				/* create the cgi_variables element and add it to the root */
+				elt = doc.createElement("cgi_variables");
+				rootElt.appendChild(elt);
+
+				/* add the cgi stuff */
+				tmpElt = doc.createElement("content_length");
+				tmpElt.appendChild(doc.createTextNode(Integer.toString(req.getContentLength())));
+				elt.appendChild(tmpElt);
+
+				tmpElt = doc.createElement("content_type");
+				tmpElt.appendChild(doc.createTextNode(req.getContentType()));
+				elt.appendChild(tmpElt);
+        System.out.println("content type: <" + req.getContentType() + ">");
+
+				tmpElt = doc.createElement("server_protocol");
+				tmpElt.appendChild(doc.createTextNode(req.getProtocol()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("scheme");
+				tmpElt.appendChild(doc.createTextNode(req.getScheme()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("server_name");
+				tmpElt.appendChild(doc.createTextNode(req.getServerName()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("server_port");
+				tmpElt.appendChild(doc.createTextNode(Integer.toString(req.getServerPort())));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("remote_address");
+				tmpElt.appendChild(doc.createTextNode(req.getRemoteAddr()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("remote_host");
+				tmpElt.appendChild(doc.createTextNode(req.getRemoteHost()));
+				elt.appendChild(tmpElt);
+        System.out.println("remote host: <" + req.getRemoteHost() + ">");
+
+				tmpElt = doc.createElement("request_method");
+				tmpElt.appendChild(doc.createTextNode(req.getMethod()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("request_uri");
+				tmpElt.appendChild(doc.createTextNode(req.getRequestURI()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("script_name");
+				tmpElt.appendChild(doc.createTextNode(req.getServletPath()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("path_info");
+				tmpElt.appendChild(doc.createTextNode(req.getPathInfo()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("path_translated");
+				tmpElt.appendChild(doc.createTextNode(req.getPathTranslated()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("remote_user");
+				tmpElt.appendChild(doc.createTextNode(req.getRemoteUser()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("auth_type");
+				tmpElt.appendChild(doc.createTextNode(req.getAuthType()));
+				elt.appendChild(tmpElt);
+				tmpElt = doc.createElement("request_url");
+				tmpElt.appendChild(doc.createTextNode(HttpUtils.getRequestURL(req).toString()));
+				elt.appendChild(tmpElt);
+
+
+				/*
+				 * create the "headers" element and sub-elements for all headers
+				 */
+				elt = doc.createElement("headers");
+				rootElt.appendChild(elt);
+        enum = req.getHeaderNames();
+        while (enum.hasMoreElements()) {
+
+            tmp = (String)enum.nextElement();
+						tmpElt = doc.createElement("header");
+            elt.appendChild(tmpElt);
+						tmpAttr = doc.createAttribute("name");
+						tmpAttr.setValue(tmp);
+						tmpElt.setAttributeNode(tmpAttr);
+						tmpElt.appendChild(doc.createTextNode(req.getHeader(tmp)));
+        }
+
+
+        /* 
+         * cookies, only if there are any
+         *
+         * sure, this is the default implementation, but I'm still trying
+         * to figure out what should be an attribute vs what should
+         * be the element content.  so, to cover both bases at once, 
+         * a cookie element looks like this:
+         *
+         *<cookie name="cookie_name">
+         *  <name>cookie_name</name>
+         *  <value>cookie_value</value>
+         *  cookie_value
+         *</cookie>
+         */
+				elt = doc.createElement("cookies");
+				rootElt.appendChild(elt);
+
+        if (((cookies = req.getCookies()) != null) && (cookies.length > 0)) {
+            for (i=0; i<cookies.length; i++) {
+
+								tmpElt = doc.createElement("cookie");
+								elt.appendChild(tmpElt);
+								tmpAttr = doc.createAttribute("name");
+								tmpAttr.setValue(cookies[i].getName());
+								tmpElt.setAttributeNode(tmpAttr);
+
+                nameElt = doc.createElement("name");
+                nameElt.appendChild(doc.createTextNode(cookies[i].getName()));
+								tmpElt.appendChild(nameElt);
+								
+                nameElt = doc.createElement("value");
+                nameElt.appendChild(doc.createTextNode(cookies[i].getValue()));
+								tmpElt.appendChild(nameElt);
+								
+                tmpElt.appendChild(doc.createTextNode(cookies[i].getValue()));
+            }
+        }
+
+
+				elt = doc.createElement("formdata");
+				rootElt.appendChild(elt);
+
+        if ((tmp = req.getQueryString()) != null) {
+            h = HttpUtils.parseQueryString(tmp);
+            enum = h.keys();
+            while (enum.hasMoreElements()) {
+
+                tmp = (String)enum.nextElement();
+                tmpA = (String[])h.get(tmp);
+
+                for (i=0; i<tmpA.length; i++) {
+                  
+                  tmpElt = doc.createElement("pair");
+                  elt.appendChild(tmpElt);
+
+                  tmpAttr = doc.createAttribute("source");
+                  tmpAttr.setValue("query_string");
+                  tmpElt.setAttributeNode(tmpAttr);
+
+                  nameElt = doc.createElement("name");
+                  nameElt.appendChild(doc.createTextNode(tmp));
+                  tmpElt.appendChild(nameElt);
+								
+                  nameElt = doc.createElement("value");
+                  nameElt.appendChild(doc.createTextNode(tmpA[i]));
+                  tmpElt.appendChild(nameElt);
+                }
+            }
+        }
+
+        try {
+            h = HttpUtils.parsePostData(req.getContentLength(),
+                                        req.getInputStream());
+        } catch (IOException e) { }
+        if ((h != null) && !h.isEmpty()) {
+
+            enum = h.keys();
+
+            while (enum.hasMoreElements()) {
+
+                tmp = (String)enum.nextElement();
+
+                tmpElt = doc.createElement("pair");
+                elt.appendChild(tmpElt);
+
+                tmpAttr = doc.createAttribute("source");
+                tmpAttr.setValue("post_data");
+                tmpElt.setAttributeNode(tmpAttr);
+
+                nameElt = doc.createElement("name");
+                nameElt.appendChild(doc.createTextNode(tmp));
+                tmpElt.appendChild(nameElt);
+								
+                nameElt = doc.createElement("value");
+                nameElt.appendChild(doc.createTextNode((h.get(tmp)).toString()));
+                tmpElt.appendChild(nameElt);
+            }
+        }
+
+        //        (new dom.DOMWriter(true)).print(doc);
+    }
+
+}
============================================================