Logo

RuleX OCL Rule User Guide

OCL rules in RuleX are used to execute constraints and queries against XML. Constraints return true or false. Queries return data. A rule is written against a context in an XML schema. A context can be a complex or simple type in the schema.

If writing rules against JSON schema, for type read definition, for element read property.

If writing rules against UML, for type read class or data type, for element read attribute or association.

This user guide describes the main OCL constructs supported in the RuleX product.

See RuleX OCL Operations Reference for the full list of standard operations supported, RuleX OCL Extensions for ISO 20022 data, and OCL Resources for general information on OCL.

Example Constraint

All students in college must be over 18.

Context: College
OCL: self.student->forAll(s | s.age > 18)

OCL Constructs

self
dot operator
Boolean operations
Numeric operations
String operations
Date operations
Enumerations
implies
if then else
let
allInstances()
Collections
size()
forAll()
select()
oclAsType()


self

Self refers to the current context. Use of the keyword self is optional. If self is not used, the current context is assumed.

These two OCL statements are identical:

self.student->forAll(s | s.age > 18)
student->forAll(s | s.age > 18)



dot operator

The dot operator is used to navigate from parent to child elements and attributes.

self.student.age


Boolean operations

= <> and or implies not xor


Numeric operations

Most operations that are available in java can be used. Some common operations are:

= <> < > <= >- + - * ⁄ sum() toString()

Examples

withdrawal.amount < balance.amount

checks that the withdrawal amount in a bank account is less than the balance.


controlSum = payment.amount->sum()

checks that a controlSum value is equal to the sum of all the individual payment amounts.



String operations

Most operations that are available in java can be used. Some common operations are:

= <> size() startsWith() endsWith() substring() matches() indexOf() equalsIgnoreCase() isNumeric() toInteger() toDate() toDecimal() contains() concat()

Where operations have the same name as a java operation e.g. substring(), matches() and indexOf(), they behave in the same way as the java operations. The matches operation uses regular expressions. Details of regular expression constructs can be found here.

Examples

name.size() < 10

checks that a name is less than ten characters long.


vatId.startsWith('GB') or vatId.startsWith('IE')

checks that a vat id starts with either the characters GB for Great Britain, or IE for Ireland.


phoneNumber.toString.startsWith('353')

checks that an integer phoneNumber starts with '353'. The integer is converted to a string to allow the characters to be compared.


bankidentifiercode.substring(4,6) = 'DE'

checks that the country code embedded in the bank identifier code (BIC) in positions 5 and 6 is DE (Germany). An example BIC is DEUTDEFF.


phoneNumber.matches("^[0-9]+$")

checks that a string phoneNumber only contains digits.


let s : string = amount.toString() in
 s.indexOf('.') = s.size() - 3

checks that a decimal amount contains exactly 2 digits after the decimal point.


email1.equalsIgnoreCase(email2)

checks that two email addresses are the same if you ignore case.


Date operations

Most operations that are available in java can be used. Some common operations are:

= <> before() after() allowedDaysInPast()

Example

tradeDate.before(settlementDate)

checks that the trade date is before the settlement date.



Enumerations

An enumeration type contains a set of named values. The values can treated as enumerated values or as strings. To reference an enumeration value use

type::value

Examples

countryCode = CountryCodeType::IE

checks that countryCode is set to the enumeration value IE on the enumeration type CountryCodeType. To reference the countryCode as a string use countryCode = 'IE'.



implies

The implies statement is used extensively in OCL. The implies statement ensures that if the first part of the statement is true, then the second part of the statement is also true.

(boolean OCL expression) implies (boolean OCL expression)

Examples

countryCode = 'IE' implies phonePrefix = '353'

checks that if the country is Ireland, then the phonePrefix must be 353.


(countryCode = 'IE' or countryCode = 'FR') implies currency = 'EUR'

checks that if the country is Ireland or France, then the currency is euro.



if then else

The if then else statement is supported in OCL. The else clause must be included. If then else statements can be nested.

if (boolean OCL expression) then (OCL expression) else (OCL expression) endif

Example

if countryCode = 'UK' then
 currency = 'GBP'
else
 currency = 'EUR'
endif

checks that if the country is the United Kingdom, then the currency must be sterling, otherwise the currency must be euro.



let

The let statement is used to define variables. Variable definitions are separated by a comma. A rule can contain more than one let statement.

let variable : type = OCL expression in

Examples

let isLowDeposit : boolean = if depositAmount < 100 then true else false endif
 in
isLowDeposit implies interestRate = 4

checks that if the amount on deposit in an account is less than 100 euro, then the interest is 4%.


let countryCode : string = bankidentifiercode.substring(4,6), phonePrefix : string = phoneNumber.substring(0,3)
 in
countryCode = 'IE' implies phonePrefix = '353'

checks that if the countryCode in a bank identifier code is IE for Ireland, then the phonePrefix in a phone number must be 353. An example bank identifier code is AIBKIE2D.


let countryCode : string = bankidentifiercode.substring(4,6)
 in
  phonePrefix : string = phoneNumber.substring(0,3)
   in
countryCode = 'IE' implies phonePrefix = '353'

checks that if the countryCode in a bank identifier code is IE for Ireland, then the phonePrefix in a phone number must be 353. This is identical to the previous example except that two let statements are used.




allInstances()

The allInstances operation returns all elements that are instances of a type. The allInstances operation can be called on a complex or simple type.

type.allInstances()

Example

Payment.allInstances().amount->sum() < 1000000

checks that the sum of the amounts for all payments (of type Payment) is less than a million.



Collections

Collections are groups of elements. A collection in OCL can be a set, a bag, an orderedSet or a sequence. The most commonly used collection is a set. Operations available on collections include:

= <> size() forAll() select() exists() count() sum() isEmpty() notEmpty() collect() excludes() excludesAll() includes() includesAll() union() append() at() first() last() indexOf() asSet() asBag() asOrderedSet() asSequence() iterate() flatten() including() excluding()

Some operations are only available for some collections.



size()

The size operation returns the number of elements in a collection. The operation is commonly used to check if the tags for an optional element exists in a section of XML.

->size()

Note on the size operation for strings: The .size() operation on a string type calculates the length of a string and is used to check if a string value has been provided. The ->size() operation can be used to determine if the string element exists. In the case of XML, the string element exists if the tags for the string element are found in the XML even if no string value is included between the tags.


Example

postalCode->size() = 0 implies (townName->size() = 1 and townName.size() > 1)

If postal code is not provided, then town name must be provided and must be at least one character in length.



forAll()

The forAll operation checks if a condition is met for all elements in a collection.

->forAll( a | boolean expression )


Examples

context: class

student->forAll(s | s.age > 18)

checks that all students in a class are over 18. A class can contain many students. Each student has an age.


student->forAll(s1, s2 | s1 <> s2 implies s1.studentId <> s2.studentId)

checks each student in a class has a unique student id.



select()

The select operation is used to create a subset of a collection based on a condition.

->select( s | expression )


Example

context: class

student->select(s | s.age >= 25)->size() < 10

checks that the number of mature students over 25 years of age in a class is less than 10. It selects all students who are over 25 from the collection of all students in the class, and calculates the number of elements in this selected subset.



oclAsType()

The oclAsType operation can be used to cast an object to another type. This can be useful in cases where two simple type elements have different types but the values need to be compared. For example, the two elements may be restrictions of a decimal type.

element.oclAsType(type)


Example

decimalAmountOfTypeA.oclAsType(decimal) = decimalAmountOfTypeB.oclAsType(decimal)

checks the decimal value in 'decimalAmountOfTypeA' is the same as the decimal value in 'decimalAmountOfTypeB'.



Copyright © 2014 - 2015 Nomos Software