Vadim Gritsenko wrote:<snip>
In that implementation I used an explicit stack to maintain the current widget. So you would have to use ${woodyStack.peek()} to access it.which actually worked for me, with JXTemplateGenerator. I'm now puzzled: how yours expression works?
It doesn't work ;-)
I wrote it by mimicing what's in Christopher's code without actually testing it.
Reading in more detail the JX implementation of <wt:form-template> and <wt:repeater>, I found that the variable containing the current widget is not "widget" but "ignored"!!
Christopher, can you confirm this? I would be good to have the "widget" or "currentWidget" variable available to crawl the widget tree from any point in the template.
This is a general issue with JXTemplate's: what should the rules about variable scoping be? Currently, any variables you set within a macro are visible within the body when it is evaluated (and hide variables with the same names defined by enclosing tag). I've attached an alternative implementation that uses the execution stack rather than an explicit stack. In this implementation the current widget is available as a variable ${woodyCurrent}. However this behavior is too permissive and can easily lead to accidental name clashes.
I need to think more about this but it should at least be possible to create variables that are private to the macro.
As regards performance, WoodyTemplateTransformer is faster. I did some informal testing using cocoon.processPipelineTo() without the xslt transformation steps using the following script:
var count = 2000;
var start = new Date();
for (var i = 0; i < count; i++) {
var strm = new java.io.ByteArrayOutputStream();
cocoon.processPipelineTo(uri, bizData, strm);
}
var end = new Date();
print("Elapsed = " + ((end - start)/1000));
print("Per instance = " + (((end - start)/1000)/count));
For "form1_template.xml" I got the following results:
<generate type=jx src="..."/> <serialize/>
Elapsed = 26.788 Per instance = 0.013394
<generate src="...">
<transform type="woody">
<serialize/>
Elapsed = 24.225
Per instance = 0.0121125
For "form_model_gui_template.xml":
<generate type=jx src="..."/> <serialize/>
Elapsed = 19.408
Per instance = 0.09704
<generate src="...">
<transform type="woody">
<serialize/>
Elapsed = 8.632
Per instance = 0.04316
I'm not sure yet why the difference is more pronounced in the latter case.
Of course the performance of the whole pipeline is dominated by xslt processing. When I included the remainder of the pipeline I got the following results for "form1_template.xml":
<generate type=jx src="..."/> <...
Elapsed = 174.19
Per instance = 0.087095
<generate src="..."> <transform type="woody"> <... Elapsed = 163.234 Per instance = 0.08161700000000001
Regards,
Chris
<jx:template xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
<jx:set var="woodyClasses" value="${java.util.HashMap()}"/>
<jx:macro name="form-template"
targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="action"/>
<jx:parameter name="method"/>
<wi:form-template xmlns:wi="http://apache.org/cocoon/woody/instance/1.0"
action="${action}" method="${method}">
<jx:set var="woodyCurrent" value="${this['woody-form']}"/>
<jx:evalBody/>
</wi:form-template>
</jx:macro>
<jx:macro name="widget" targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="widget" value="${woodyCurrent.getWidget(id)}"/>
<jx:choose>
<jx:when test="${widget.getSize() != null}"> <!-- repeater -->
<jx:set var="lastRow" value="${widget.getSize() - 1}"/>
<jx:forEach varStatus="loop" begin="0" end="${lastRow}">
<jx:set var="woodyCurrent" value="${widget.getRow(loop.index)}"/>
${row.generateSaxFragment(cocoon.consumer, locale)}
<jx:evalBody/>
</jx:forEach>
</jx:when>
<jx:otherwise>
${widget.generateSaxFragment(cocoon.consumer, locale)}
<jx:evalBody/>
</jx:otherwise>
</jx:choose>
</jx:macro>
<jx:macro name="repeater-widget-label"
targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:parameter name="widget-id"/>
<jx:set var="repeater" value="${woodyCurrent.getWidget(id)}"/>
${repeater.generateWidgetLabel(this['widget-id'], cocoon.consumer)}
</jx:macro>
<jx:macro name="widget-label"
targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="widget" value="${woodyCurrent.getWidget(id)}"/>
${widget.generateLabel(cocoon.consumer)}
</jx:macro>
<jx:macro name="repeater-size"
targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="widget" value="${woodyCurrent.getWidget(id)}"/>
${widget.generateSize(cocoon.consumer)}
</jx:macro>
<jx:macro name="repeater-widget"
targetNamespace="http://apache.org/cocoon/woody/template/1.0"
xmlns:wt="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="widget" value="${woodyCurrent.getWidget(id)}"/>
<jx:set var="lastRow" value="${widget.getSize() - 1}"/>
<jx:forEach varStatus="loop" begin="0" end="${lastRow}">
<jx:set var="woodyCurrent" value="${widget.getRow(loop.index)}"/>
<jx:evalBody/>
</jx:forEach>
</jx:macro>
<jx:macro name="continuation-id"
targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<wi:continuation-id
xmlns:wi="http://apache.org/cocoon/woody/instance/1.0">${cocoon.continuation.id}</wi:continuation-id>
</jx:macro>
<jx:macro name="class" targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="ignored" value="${woodyClasses.put(id, macro.body)}"/>
</jx:macro>
<jx:macro name="new" targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:eval select="${woodyClasses.get(id)}"/>
</jx:macro>
<jx:macro name="struct" targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="woodyCurrent" value="${woodyCurrent.getWidget(id)}"/>
<wi:struct xmlns:wi="http://apache.org/cocoon/woody/instance/1.0" id="${id}">
<jx:evalBody/>
</wi:struct>
</jx:macro>
<jx:macro name="union" targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:set var="woodyCurrent" value="${woodyCurrent.getWidget(id)}"/>
<wi:union xmlns:wi="http://apache.org/cocoon/woody/instance/1.0" id="${id}">
<jx:evalBody/>
</wi:union>
</jx:macro>
<jx:macro name="case" targetNamespace="http://apache.org/cocoon/woody/template/1.0">
<jx:parameter name="id"/>
<jx:if test="${woodyCurrent.value == id}">
<jx:evalBody/>
</jx:if>
</jx:macro>
</jx:template>
