Accessing unknown multiple occurrences of an element

To access repeating fields in a message, you must use a construct that can iterate over all instances of a repeating field.

About this task

You are likely to deal with messages that contain repeating fields with an unknown number of repeats (such as the Item field in Example message).

To write a filter that takes into account all instances of the Item field, you need to use a construct that can iterate over all instances of a repeating field. The quantified predicate allows you to execute a predicate against all instances of a repeating field, and collate the results.

For example, you might want to verify that none of the items that are being ordered has a quantity greater than 50. To do this you could write:

FOR ALL Body.Invoice.Purchases."Item"[] 
    AS I (I.Quantity <= 50)

With the quantified predicate, the first thing to note is the brackets [] on the end of the field reference after FOR ALL. These tell you that you are iterating over all instances of the Item field.

In some cases, this syntax appears unnecessary because you can get that information from the context, but it is done for consistency with other pieces of syntax.

The AS clause associates the name I with the current instance of the repeating field. This is similar to the concept of iterator classes used in some object oriented languages such as C++. The expression in parentheses is a predicate that is evaluated for each instance of the Item field.

A description of this example is:

Procedure

Iterate over all instances of the field Item inside Body.Invoice.
For each iteration:
  1. Bind the name I to the current instance of Item.
  2. Evaluate the predicate I.Quantity <= 50.
    If the predicate:
    • Evaluates to TRUE for all instances of Item, return TRUE.
    • Is FALSE for any instance of Item, return FALSE.
    • For a mixture of TRUE and UNKNOWN, return UNKNOWN.

Results

The above is a description of how the predicate is evaluated if you use the ALL keyword. An alternative is to specify SOME, or ANY, which are equivalent. In this case the quantified predicate returns TRUE if the sub-predicate returns TRUE for any instance of the repeating field. Only if the sub-predicate returns FALSE for all instances of the repeating field does the quantified predicate return FALSE. If a mixture of FALSE and UNKNOWN values are returned from the sub-predicate, an overall value of UNKNOWN is returned.

In the following filter expression:

FOR ANY Body.Invoice.Purchases."Item"[]  
    AS I (I.Title = 'The XML Companion')

the sub-predicate evaluates to TRUE. However this next expression returns FALSE:

FOR ANY Body.Invoice.Purchases."Item"[] 
    AS I (I.Title = 'C Primer')

because the C Primer is not included on this invoice. If some of the items in the invoice do not include a book title field, the sub-predicate returns UNKNOWN, and the quantified predicate returns the value UNKNOWN.

To deal with the possibility of null values appearing, write this filter with an explicit check on the existence of the field, as follows:
FOR ANY Body.Invoice.Purchases."Item"[] 
	 AS I (I.Book IS NOT NULL AND I.Book.Title = 'C Primer')

The predicate IS NOT NULL ensures that, if an Item field does not contain a Book, a FALSE value is returned from the sub-predicate.

You can also manipulate arbitrary repeats of fields within a message by using a SELECT expression, as described in Referencing columns in a database.

You can refer to the first and last instances of a repeating field using the [>] and [<] array indexes, and to instances relative to the first and last, even if you do not know how many instances there are. These indexes are described in Accessing known multiple occurrences of an element.

Alternatively, you can use the CARDINALITY function to determine how many instances of a repeating field there are. For example:

DECLARE I INTEGER CARDINALITY(Body.Invoice.Purchases."Item"[])