cocoon-docs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject [Cocoon Wiki] New: XfolioOpenOfficeGeneration
Date Tue, 13 Jul 2004 23:28:49 GMT
   Date: 2004-07-13T16:28:48
   Editor: GlorieuxFrédéric <>
   Wiki: Cocoon Wiki
   Page: XfolioOpenOfficeGeneration

   no comment

New Page:

= Abstract =

XfolioOpenOffice generation, one more time.
The issue is discussed in more than one place (sometimes by me)
this is my last cocoon solution to have a flat oo xml file,
with _caching_ ! 

= Status =

It works for me, in hope this helps others.
For Cocoon 2.1.5
Could be proposed as a commit in default cocoon ?

= Usage =

See [xfolio.xmap] 

  <map:match pattern="**.oo">
    <map:generate type="xsp" src="actions/oo.xsp">
      <map:parameter name="sxw" value="{context-attr:xfolio.efolder}{1}.sxw"/>
    <map:serialize type="xml"/>

= How it works ? =

I need an OpenOffice generator, not only to provide an HTML view or some other transformation,
but also to extract metadata on vast amount of documents. I read all I can about OpenOffice
generation and search for the best solution which should be
 * easy
 * fast
 * cacheable

  == Forget ==
 * default src="jar:myzip!myentry.xml" seems to load the file entry in memory,
but never remember the changes (isnt'it the goal to load a class from a jar one type ?)

  == Forrest ==

The best I found for now come from Forrest, using the new zip protocol from cocoon, able to
resolve things like src="zip://content.xml@{folder}/test.sxw". This is a part of the trick.
The problem of their solution is to use a cinclude transformer, which is not cacheable. I
mean, you need to regenerate your aggregation each time it is requested. This is not a big
problem in Forrest context (essentially generate a site), but on a real life server...

Their solution looks like that

<map:generate src="transform/cocoon/dummy.xml"/>
<map:transform src="transform/cocoon/sxw2oo.xsl">
  <map:parameter name="src" value="{context-attr:xfolio.efolder}{1}.sxw"/>
<map:transform type="cinclude"/>
<map:serialize type="xml"/>

The dummy.xml is only there because you need something to begin with pure cocoon. 
The job is done by the XSL, to write something like that.
<office:document xmlns:**>
  <c:include select="/*/*">
    <xsl:attribute name="src">zip://meta.xml@<xsl:value-of select="$src"/></xsl:attribute>
  <c:include select="/*/*">
    <xsl:attribute name="src">zip://content.xml@<xsl:value-of select="$src"/></xsl:attribute>

Problem are
 * an Xpath include is expensive (all document need to be loaded as DOM)
 * Cinclude (like Xinclude) haven't seem to be cacheable for me

You may say, try a {{<map:agreggate/>}}... I tried, and produce so much problems 
of validation that I stopped.

  == oo.xsp ==

The attached xsp do quite the same job as the excellent Forrest solution, 
with these differences
 * the generator is controlled and know the files on which check changes : 
the sxw, essentially (and also the xsp, for debug)

 * performances
    * direct pipe cost ~10 ms
    * xinclude cost ~160ms 
    * cinclude ~320ms
    * oo.xsp generator cost ~200ms on first call, but is _cached_ (~40 ms on second call)


= References =

  == useful ==

 * [*checkout*/xml-forrest/src/core/context/forrest.xmap
Forrest Open Office]
 * [ XSPCaching]
 * [*checkout*/cocoon-2.1/src/webapp/samples/xsp/xsp/Attic/cacheable.xsp]
 * [*checkout*/cocoon-2.1/src/java/org/apache/cocoon/transformation/]
 * [*checkout*/cocoon-2.1/src/java/org/apache/cocoon/components/source/impl/ZipSourceFactory.html]
 * [*checkout*/cocoon-2.1/src/java/org/apache/cocoon/generation/FileGenerator.html]

  == bad examples ==

 * [  JarProtocolExample]
 * [ OpenOfficeGeneration]

= Rights =
(c) 2003, 2004,,
Licence : GPL []
 * created: 2003-07-10

'''FIXME: is it possible to update an attachement ?'''

= the code =

<xsp:page xmlns:xsp="">
    // artificial slowdown to make the effects of the cache visible
    final int DELAY_SECS = 2;

    /** The input source */
    protected Source sxwSource;
    protected Source xspSource;

     * From org.apache.cocoon.generation.FileGenerator
     * Setup the file generator.
     * Try to get the last modification date of the source for caching.

    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
        throws ProcessingException, SAXException, IOException {

        super.setup(resolver, objectModel, src, par);
        String sxw="";
        try {
          sxw = (String)parameters.getParameter("sxw");
          this.sxwSource = super.resolver.resolveURI(sxw);
        } catch (SourceException se) {
            throw SourceUtil.handle("oo.xsp, failed resolution sxw='" + sxw +"'.", se );
        } catch (ParameterException pe) {
           throw new ProcessingException ("oo.xsp, sxw param not found" , pe);
        try {
            this.xspSource = super.resolver.resolveURI(src);
        } catch (SourceException se) {
            throw SourceUtil.handle("oo.xsp, failed resolution xsp='" + src + "'.", se);


     * Recycle this component.
     * All instance variables are set to <code>null</code>.
    public void recycle() {
        if (null != this.sxwSource) {
            this.sxwSource = null;
        if (this.xspSource != null) {
            this.xspSource = null;
    * Generate the unique key for the cache.
    * This key must be unique inside the space of this XSP page, it is used
    * to find the page contents in the cache (if getValidity says that the
    * contents are still valid).
    * This method will be invoked before the getValidity() method.
    * @return The generated key or null if the component
    *         is currently not cacheable.
    public getKey() {
        String key=(this.sxwSource != null)?this.sxwSource.getURI():null;
        return key;

    * Generate the validity object, tells the cache how long to
    * keep contents having this key around.
    * Before this method can be invoked the getKey() method
    * will be invoked.
    * In our case, validity combine the xsp file and the sxw file.
    * @return The generated validity object or null if the
    *         component is currently not cacheable.
    public SourceValidity getValidity() {
      AggregatedValidity out=new AggregatedValidity();
      if (this.sxwSource != null) out.add(this.sxwSource.getValidity());
      if (this.xspSource != null) out.add(this.xspSource.getValidity());
      return out;


    <office:document xmlns:office="" xmlns:style=""
xmlns:text="" xmlns:table=""
xmlns:draw="" xmlns:fo=""
xmlns:xlink="" xmlns:dc="" xmlns:meta=""
xmlns:number="" xmlns:svg=""
xmlns:chart="" xmlns:dr3d=""
xmlns:math="" xmlns:form=""
xmlns:script="" xmlns:config=""
office:class="text" office:version="1.0">

This debug commodity makes you sure that something is cached
(DELAY_SECS if create, less if cached)

          // slowdown page generation.
            try {
              Thread.sleep(DELAY_SECS * 1000L);
            } catch (InterruptedException ie) {
              // Not much that can be done...


// from org.apache.cocoon.transformation.XIncludeTransformer
SourceUtil.toSAX(super.resolver.resolveURI("zip://meta.xml@"+this.sxwSource.getURI()), new
new IncludeXMLConsumer(this.contentHandler));

an xpointer may be nicer (to conform to ooxmlflat), but much more
expensive, because it needs a complete DOM in memory




View raw message