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);
+ }
+
+}
============================================================