Expressions for workitem manipulation

Manipulating the payload of the workitem passing through them is the task of these expressions.

set

If you'd like to set the value of a field of a workitem or the value of a variable in the scope of a flow, you can use the 'set' expression.


  <set
      field="status"
      value="reviewed"
  />

will set the value of the field 'status' to the StringAttribute "reviewed". If the field named 'status' is not already present, it will be created, else, it will be overriden.


  <set
      field="status"
      field-value="status_chosen_by_bob"
  />

will copy the value of the field 'status_chosen_by_bob' as the value of the field 'status'.


  <set
      variable="counter"
      value="1"
  />

will set the value of the variable 'counter' to '1'.


  <set
      field="count"
      variable-value="counter"
  />

will set the value of the field 'count' of the current workitem to the value of the variable 'counter'

There is a 'type' attribute appeared in the 'set' expression. This attribute has only effect when setting a field.


  <set
      field="successful"
      value="false"
      type="boolean"
  />

This example will set a boolean field named 'successful' with a value set to 'false'. Available types are 'long', 'integer', 'double' and 'boolean'. When type is not present, fields will be set as 'string'.

With variables, if you put a forward slash '/' in front of the variable name, the engine will look at the root expression of the flow instance. It provides an easy mean for communicating between expressions, it is especially useful with the 'when' expression (which is explained in a few paragraphs).

setting the value of a subfield

Since OpenWFE 1.6.2, it's possible to directly set the value of a subfield. In the following snip of flow, the field 'customer' holds a MapAttribute value (a StringMapAttribute possibly) and thus it's possible to write :


    <sequence>
        <set field="customer.firstname" value="Ed" />
        <set field="customer.lastname" value="Hoover" />
    </sequence>

For a document management system, one might imagine writing pool code like :


    <sequence>
        <if>
            <equals value="${f:document.index.tiff}" other-value="true" />
            <!-- then -->
            <set field="document.url" field-value="document.index.tiff.url" />
            <!-- else -->
            <set field="document.url" field-value="document.index.pdf.url" />
        </if>
    </sequence>

(Note the mix in the usage of the regular notation with the 'dollar notation')

This example may also be written in that way :


    <set field="document.url">
        <if>
            <equals value="${f:document.index.tiff}" other-value="true" />
            <!-- then -->
            <f>document.index.tiff.url</f>
            <!-- else -->
            <f>document.index.pdf.url</f>
        </if>
    </set>

nesting the values inside of the 'set'

You're not limited to the 'value' attributes, you can use a nested value inside of the 'set' expression.

If you have a multiline value for a field or a variable you can nest it inside the set expression :


  <set field="successful">
.
this is the value I put in my field 
.
.
named 'successful'.
.
  </set>

If the value is using special chars, you can use XML's CDATA notation to protect it.

There is another way of determining values. This way is only useful for workitem attributes (but you could sotre attributes in variables without problem).


    <sequence>

        <set field="customer">
            <a>
            <smap>
                <entry>
                    <string>name</string>
                    <string>Shostakovitch</string>
                </entry>
                <entry>
                    <string>city</string>
                    <string>Petrograd</string>
                </entry>
                <entry>
                    <string>car</string>
                    <smap>
                        <entry>
                            <string>make</string>
                            <string>Lada</string>
                        </entry>
                        <entry>
                            <string>model</string>
                            <string>147 TD</string>
                        </entry>
                    </smap>
                </entry>
            </smap>
            </a>
        </set>

        <set field="customers">
            <a>
            <list>
                <string>0 Alpha</string>
                <string>1 Bravo</string>
                <string>2 Charly</string>
                <string>3 Delta</string>
                <string>4 Echo</string>
                <string>5 Foxtrott</string>
                <string>6 Gamma</string>
                <string>7 ${customer.name}</string>
            </list>
            </a>
        </set>

        <set field="misc">
            <a>
            <list>
                <string>${f:customer.name}</string>
                <string>${f:customer.car.model}</string>
                <string>${f:customers.3}</string>
            </list>
            </a>
        </set>

    </sequence>

The last 'set' is interesting and shows how you can fetch a many from deep inside the workitem.

Useful : nesting an 'if' within the 'set'


    <set variable="color">
        <if> 
            <equals value="${black-and-white}" other-value="true" />
            <q>gray-150</q>
            <q>blue</q>
        </if>
    </set>

if the variable 'black-and-white' is set to 'true', the variable 'color' will be set to 'gray-150', else to 'blue'.

<set> and scope

If <set> has to set a variable which is already bound, it will do the 'rebinding' at exactly the same level. Else, it will set a new local binding for that variable name.

Here is a small example with the given output each time (for the sake of simplicity, the print expression is used. This expression outputs to the standard out pipe (the console)).


    <sequence>

        <set variable="v0" value="value" />
        <sub0 />
        <print>${v0}</print>

            <!-- this block of code will emit :

                sub0.in  : value
                sub0.out : sub0.value
                sub0.value

            notice how the variable v0 got changed outside of the subprocess
            scope -->

        <sub0 v0="other value" />
        <print>${v0}</print>

            <!--

                sub0.in  : other value
                sub0.out : sub0.value
                sub0.value

            as the variable v0 was bound at subprocess level, its value in
            the main process body remain unaffected -->

        <set variable="v0" value="global value" />
        <sub2/>
        <print>${v0}</print>

            <!--

                sub2.in  : global value
                sub2.out : sub2.value
                global value

            as v0 is prefixed with "./" in the subprocess sub2, it is 
            automatically bound locally (at subprocess level) thus,
            the variable as bound in the main process body remains unaffected 
            -->

    </sequence>

    <process-definition name="sub0">
        <sequence>
            <print>sub0.in  :  ${v0}</print>
            <set variable="v0" value="sub0:value" />
            <print>sub0.out : ${v0}</print>
        </sequence>
    </process-definition>

    <process-definition name="sub1">
        <sequence>
            <print>sub1.in  :  ${v0}</print>
            <set variable="v0" value="sub1:value" />
            <print>sub1.out : ${v0}</print>
        </sequence>
    </process-definition>

    <process-definition name="sub2">
        <sequence>
            <print>sub2.in :  ${v0}</print>

            <set variable="./v0" value="sub2:value" />
                <!-- setting locally -->

            <print>sub2.out : ${v0}</print>
        </sequence>
    </process-definition>

unset

Unbinds a variable or a field in the same way that 'set' binds it.

inc

This expressions allows to add a value to a field or a variable. Consider this snippet of a flow :


    <sequence>
        <set field="index" value="0" />
        <participant ref="alpha" />
   
        <inc field="index" value="1" />
        <participant ref="bravo" />
   
        <inc field="index" value="1" />
        <participant ref="charly" />
    </sequence>

Participant 'alpha' will receive a workitem whose 'index' field is set to 0. Participant 'bravo' will receive a 1 and 'charly' a 2.

Another example inside a recursion, the subdefinition will execute thrice :


<?xml version="1.0" encoding="UTF-8"?> 
<process-definition 
    name="flow" 
    revision="1.14"
>

    <sequence>
        <set field="index" value="0" />
        <subprocess ref="review" />
    </sequence>

    <process-definition name="review">
        <sequence>
            <participant ref="role-alpha" />
            <inc field="index" />
            <if>
                <lesser-than field-value="index" other-value="4" />
                    <!-- 4 iterations -->
                <subprocess ref="review" />
            </if>
        </sequence>
    </process-definition>

</process-definition>