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
Body.Invoice
.
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.
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"[])