Including code dynamically from a sheet

Hi all,

In the scope of the GSoC Map Application, we’d like to use the Solr macros from a MapSheet in order to query the map data over the Solr API, reusing the facet user interface code that exists already, if possible. We’re hitting an issue that can be expressed as follows in a generic way, imho, while trying to include / render code dynamically from a sheet.

Step 1

Create page Main.MySheet with the content below, which defines two macros, and calls the second one. The second one renders dynamically another page containing some Velocity code. This is typically what happens with the Solr facet displayers, which are defined in their own pages (such as Main.SolrTypeFacet) and get called from Main.SolrSearchMacros whenever needed. This is handy in terms of dynamicity.

{{velocity}}

#macro (macro1 $param1)
  Hello $param1
#end

#macro (macro2)
  ## The page name containing the target script can be set dynamically.
  #set ($scriptPageName = 'Main.MyScript')
  #set ($scriptPage = $xwiki.getDocument($scriptPageName))
  $!scriptPage.getRenderedContent(false)
#end

#macro2

{{/velocity}}

Step 2

Create page Main.MyScript with the content below:

{{velocity}}
#set ($param = "John")
{{html clean="false"}}#macro1($param){{/html}}
{{/velocity}}

Step 3

Go to Main.MySheet: you should get “Hello John”, as expected (courtesy XWiki magic).

Step 4

  • Create a class Main.MyClass with any arbitrary property.
  • Define an XWiki sheet binding with page Main.MySheet for this class.
  • Create page Main.MyObject and attach an object of class Main.MyClass to it.

Step 5

Head to page Main.MyObject in view mode: while one would expect “Hello John” as well (I think), one gets “#macro1($param)”.

Question

Would you know if there’s a way to get macro1 executed dynamically when rendered from a sheet, hence not only from a “standard” page?

Cheers

1 Like

{{include reference="Main.MySheet" /}} ?

Thank you @evalica, but the goal is to get the code executed from Main.MySheet itself first (sorry I was unclear by mentioning “from a sheet”), not from another sheet. Since the code does not even work for Main.MySheet (when viewing Main.MyObject), I doubt it will work better when included from another one, or do you things differently?

Hi all, Meantime @lucaa found a possible solution, which consists in using the “#evaluate” Velocity macro as follows:

  #set ($script = $!scriptPage.content.replaceAll('\{\{/{0,2}velocity\}\}', ''))
  #evaluate($script)

This way, the macro defined dynamically in Main.Script is executed as expected not only from Main.MySheet, but also from Main.MyObject. However it looks more like a workaround, I guess we should investigate why the Velocity contexts seem to differ between pages Main.MyObject and Main.Script while calling $scriptPage.getRenderedContent(false) – I’m ccing the transformation experts @vmassol @tmortagne

Cheers

1 Like

Hi all,
Thanks @lucaa for the possible fix.
Evaluating the script for some reason does not execute the macros which is very troublesome. Suppose we have {{html}} macro inside a script, the related velocity code will execute but the macro will remain as is.
For example, if we have the following script:

{{html clean="false"}}
  #set ($testString = "Some text for testing")
  $testString
{{/html}}

The output of #evaluate macro for this script will be:

{{html clean="false"}}
  Some text for testing
{{/html}}

The html macro remains. Same for all other macros e.g. {{velocity}}. As opposed to before which only removes {{velocity}} macro, I found a possible workaround for removing all kinds of macros and then evaluate the script. That can be done using:

#set ($script = $!scriptPage.content.replaceAll('\{\{(.+?)\}\}', '')) ## regex changed
#evaluate($script)

I hope we can bring a real fix for this. :slight_smile:
Thanks.