Search code examples
javahtmlapache-cocoon

Apache Cocoon 2.2: Return paramater from action and use it in HTML page to fill table


What I want to do?

I'm working on a Apache Cocoon Project and want to find solution to return paramaters in HTML pages.

I need to get the parameter, which has ArrayList type, and use it in HTML page in order to fill a table. How can I do this? Is it correct to set a request parameter? If yes, then how to use it inside HTML code? If no, then how to return the parameter correctly?

ActionClass.java

public class ActionClass implements Action, ThreadSafe{


     public Map act(Redirector rdrctr, org.apache.cocoon.environment.SourceResolver sr, Map map, String string, Parameters params) throws Exception {


               // READ REQUEST
               Request request = ObjectModelHelper.getRequest(map);


               // DO SOMETHING XQUERY VIA BASEX, SPARQL RDFSTORE WHATEVER
               ArrayList<ResultBean> results = xquery();


               Map sitemapParams = new HashMap();

               // SET REQUEST PARAMETER
               request.setAttribute("results",results);

               return sitemapParams;
    }

}

ResultBean.java

package com.kiddo.grlegislation;

public class ResultBean {

    private String id;
    private String title;
    private String type;

    public void setId(String i){
        this.id = i;
    };

     public void setTitle(String t){
        this.title = t;
    };

    public String getId(){
        return this.id;
    };

    public String getTitle(){
        return this.title;
    };



}

Solution

  • First of all, are you sure that you need an Action? Actions are meant to act somehow (update something in the database, invoke a web service, etc). If you just need to generate content, a Generator class could be a better fit for you...

    Anyway... How could you return something from an Action into HTML? Lets see it with an example:

    Action class: because it extends Action, it must return a Map. Just add there whatever data you need to pass to your HTML:

    package com.stackoverflow;
    public class ActionClass extends Action {
        public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters params) {
            Map<String, String> sitemapParams = new HashMap<String, String>();
            sitemapParams.put("myVariable", "hello world!");
            return sitemapParams;
        }
    }
    

    sitemap.xmap: in your sitemap file, you can access any data returned by the Action, by placing it's key between brackets. Then you can pass it to your HTML generator:

    <map:components>
        <map:actions>
            <map:action name="myAction" src="com.stackoverflow.ActionClass" />
        </map:actions>
    </map:components>
    ...
    <map:match ...>
        <map:generate ... />
        <map:act type="myAction">
            <map:transform src="myTransformation.xsl">
                <map:parameter name="something" value="{myVariable}"/>
            </map:transform>
        </map:act>
        <map:serialize .../>
    </map:match>
    

    myTransformation.xsl: your XSLT file should read the data and embed it into your HTML:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:param name="something" select="'default value if you wish to specify one'"/>
    
        <xsl:template match="xxx">
            <html><body>...
                <xsl:value-of select="$something" />
            ...</body></html>
        </xsl:template>
    </xsl:stylesheet>
    

    You can get more information about Actions, Generators and the sitemap in this page. It's from Apache Cocoon 2.1 documentation, but it also applies to 2.2.


    Alternative approach, with a Generator:

    Generator class: this file builds a XML document, which is then passed into the pipeline. You could have something like this:

    import org.xml.sax.InputSource;
    import org.xml.sax.XMLReader;
    import org.xml.sax.helpers.XMLReaderFactory;
    ...
    
    public class GeneratorClass extends AbstractGenerator {
    
        private String foo;
    
        @Override
        public void setup(SourceResolver resolver, Map objectModel, String src, Parameters params) throws ProcessingException, SAXException, IOException {
            super.setup(resolver, objectModel, src, params);
            // you can read input parameters in here:
            foo = params.getParameter("someParameter");
        }
    
        public void generate() throws IOException, SAXException, ProcessingException {
            ArrayList<ResultBean> beans = xQuery(foo);
    
            // Let's build the XML document. I'll do it by manually appending text strings,
            // but there is no need, we could just use Xstream or any similar library
            StringBuilder xml = new StringBuilder();
            xml.append("<results>");
    
            // Iterate through the array list...
            for (ResultBean b : beans) {
                xml.append("<result>");
                xml.append("<id>").append(b.getId()).append("</id>");
                xml.append("<title>").append(b.getTitle()).append("</title>");
                xml.append("</result>");
            }
    
            // ... and we end the XML string
            xml.append("</results>");
    
            // Return the XML to Cocoon's pipeline
            XMLReader xmlreader = XMLReaderFactory.createXMLReader();
            xmlreader.setContentHandler(super.xmlConsumer);
            InputSource source = new InputSource(new StringReader(xml.toString()));
            xmlreader.parse(source);
            try {
                this.finalize();
            } catch (Throwable e) {
            }
        }
    
    }
    

    Sitemap.xmap: you just need to call your generator, and then apply your XSLT to the generated XML:

    <map:components>
        <map:generators>
            <map:generator type="myGenerator" src="com.stackoverflow.GeneratorClass" />
        </map:generators>
    /<map:components>
    
    <map:generate type="myGenerator">
        <!-- if you need to pass input data to the generator... -->
        <map:parameter name="someParameter" select="{request-param:something}" />
    </map:generate>
    <map:transform src="myTransformation.xsl" />
    <map:serialize type="html"/>
    

    myTransformation.xsl:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="/">
        <html>
            <head></head>
            <body>
                <table>
                    <xsl:for-each select="results/result">
                        <tr>
                            <td><xsl:value-of select="id/text()"/></td>
                            <td><xsl:value-of select="title/text()"/></td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
    

    You can get more info about Cocoon generators here. Once again, it's an official tutorial for Cocoon 2.1, but it's also valid for Cocoon 2.2.