Adapt Text

The Imixs WorkflowService provides the method ‘adaptText(text, document)’ which can be called when a text fragment should be adapted to a custom format or custom values.

String result = workflowService.adaptText(text, workitem);

The Imixs WorkflowService provides the following adapter classes:

  • TextItemValueAdapter
  • TextFileDataAdapter
  • TextForEachValueAdapter
  • TextForEachChildAdapter
  • TextForEachRefAdapter
  • TextPropertyAdapter

The adapter classes are called by the CDI observer pattern which allows to implement custom text adapters as well. See the section ‘Custom Text Adapters’ below for more details.


Adapting Item Values

The TextItemValueAdapter adapts a text fragment containing the XML tag <itemvalue> with the item value of an item. This adapter is useful if a string constant needs to be updated with values from the current workitem.

For example, a BPMN mail message text can be adapted with information from the current workitem:

The invoice was generated by <itemvalue>namcreator</itemvalue>
at <itemvalue format="EEE, MMM d, yyyy">$created</itemvalue>

This message text-block will be automatically adapted with the workitem properties ‘namcreator’ and ‘$created’ into:

The invoice was generated by Ralph
at Wed, Jul 4, 2010

To format a number you can also use the Java standard number formatting:

<itemvalue format="#,###,##0.00" locale="de_DE">price</itemvalue>

Format multi-value Items

If an item contains a multi-value list, all values can be separated by a character sequence defined by the separator attribute. For example, the following message text based on an item _parts with the values {"pants", "shirt", "jacket"} and a separator ", ":

The following item has been ordered: <itemvalue separator=", ">_parts</itemvalue>

will be replaced with:

The following item has been ordered: pants, shirt, jacket

Note: If no separator is defined, only the first value will be returned.

To get the last value of a multi-value list the position attribute can be set to last:

The last order item was: <itemvalue position="last">_parts</itemvalue>

Format date/number values by locale

To format a date or number value into a language specific format the format and locale attributes can be used:

The Date in german format is: <itemvalue format="EEEE, d. MMMM yyyy" locale="de_DE">datdate</itemvalue>.

Cross-Workitem References

The optional ref attribute allows reading an item value from a different workitem. The attribute value is the name of an item in the current workitem whose value holds the $uniqueId of the referenced workitem.

<!-- Read customer.name from the workitem referenced by $workitemref -->
<itemvalue ref="$workitemref">customer.name</itemvalue>

<!-- Read invoice.total from the workitem referenced by agent.ref.invoice -->
<itemvalue ref="agent.ref.invoice" format="#,###.00" locale="de_DE">invoice.total</itemvalue>

This is particularly useful in AI prompt templates where an Agent workflow needs to access data from multiple related business processes:

<prompt role="user">
  Customer: <itemvalue ref="$workitemref">customer.name</itemvalue>
  Invoice total: <itemvalue ref="agent.ref.invoice" format="#,###.00">invoice.total</itemvalue>
</prompt>

Referenced workitems are cached within a single adaptText() call to avoid repeated database lookups.


Adapting File Content

The TextFileDataAdapter resolves the text content of file attachments stored in a workitem and inserts it into a text template. The tag content is treated as a regular expression matched against the file names of all attachments.

The "text" metadata item of each matching file is read — this item is expected to hold the pre-extracted plain text content of the file (e.g. produced by an OCR or PDF-to-text pipeline).

<!-- Match a specific file -->
<filedata>invoice\.pdf</filedata>

<!-- Match all PDFs -->
<filedata>^.+\.pdf$</filedata>

<!-- Match all attachments -->
<filedata>.*</filedata>

Separator

When multiple files match the pattern, their text content is concatenated. The optional separator attribute controls the string inserted between individual file contents. The escape sequences \n and \t are supported. If no separator is defined a double newline is used as default.

<filedata separator="\n---\n">^.+\.pdf$</filedata>

Cross-Workitem References

Like the TextItemValueAdapter, the TextFileDataAdapter supports the ref attribute to read file attachments from a different workitem:

<!-- Read invoice.pdf from the workitem referenced by $workitemref -->
<filedata ref="$workitemref">invoice\.pdf</filedata>

<!-- Read all PDFs from a referenced workitem -->
<filedata ref="agent.ref.invoice" separator="\n---\n">^.+\.pdf$</filedata>

Note: If no attachment matches the pattern the tag is replaced with an empty string and a warning is written to the log. No exception is thrown so that the rest of the template is still processed normally.


The For-Each-Value Adapter

The TextForEachValueAdapter can be used to format text fragments with the for-each-value tag. The adapter iterates over the value list of a specified item:

<for-each-value item="_partid">
  Order-No: <itemvalue>_orderid</itemvalue> - Part ID: <itemvalue>_partid</itemvalue><br />
</for-each-value>

In this example the for-each block will be executed for each single value of the item _partid. Within the for-each block it is possible to access the current value of the iteration as well as any other values of the current document. The result may look like:

Order-No: 111222 - Part ID: A123
Order-No: 111222 - Part ID: B456

The For-Each-Child Adapter

In case an item contains an embedded list of child ItemCollections the TextForEachChildAdapter can be used. The adapter processes the template in the context of each embedded ItemCollection:

<for-each-child item="_orderitems">
  <itemvalue>_orderid</itemvalue>: <itemvalue>_price</itemvalue>
</for-each-child>

The result may look like:

Order ID: A123: 50.55
Order ID: B456: 150.10

The For-Each-Ref Adapter

The TextForEachRefAdapter iterates over a list of workitem references stored in a specified item. For each reference the workitem is loaded and the template is processed in its context:

<for-each-ref item="_orderitems">
  <itemvalue>_orderid</itemvalue>: <itemvalue>_price</itemvalue>
</for-each-ref>

The result may look like:

Order ID: A123: 50.55
Order ID: B456: 150.10

Adapting Property Values

The TextPropertyAdapter adapts text blocks with values stored in the imixs.properties file. A static message text will be automatically replaced with the corresponding property value if the propertyvalue tag is used:

Please use the following Link to open the Application:
<propertyvalue>dbRootURL</propertyvalue>

The values from the imixs.properties file are accessed by the PropertyService.


Using Text Adapters in AI Prompt Templates

All text adapters work seamlessly inside AI prompt templates. The adaptText() method is called before the prompt is sent to the LLM, so the full power of the adapter pipeline is available:

<PromptDefinition>
  <prompt role="system">
    You are a financial assistant analyzing business data.
  </prompt>
  <prompt role="user">
    ## Customer
    <itemvalue ref="$workitemref">customer.name</itemvalue>
    <itemvalue ref="$workitemref">customer.address</itemvalue>

    ## Invoice
    <itemvalue ref="agent.ref.invoice" format="#,###.00" locale="de_DE">invoice.total</itemvalue>

    ## Invoice Document
    <filedata ref="agent.ref.invoice">invoice\.pdf</filedata>

    ## Related Orders
    <for-each-ref item="agent.refs.orders">
      - Order <itemvalue>order.id</itemvalue>: <itemvalue>order.amount</itemvalue>
    </for-each-ref>
  </prompt>
</PromptDefinition>

Custom Text Adapters

An application can extend the adaptText() method by implementing a CDI bean with an @Observes method. The CDI event TextEvent is fired to all registered observers:

@Stateless
public class CustomTextAdapter {
    // Observer method for CDI TextEvents
    public void onEvent(@Observes TextEvent event) {
        String text = event.getText();
        text += " Hello World";
        event.setText(text);
    }
}

Adapt a TextList

A custom adapter can also adapt a text into a text list. For example a custom adapter can compute a list of values based on a text pattern. The custom adapter sets the result list with the method setTextList(). This feature is used by the AccessPlugin method mergeRoles where the adapter is expected to provide a list of roles.