5.5. Forms

Forms are data structures used to validate input and output data and to do some basic normalization in order to make data accessible in a uniform way. Forms are defined in a data definition language (DDL) and translated by a compiler at startup. Those compilers are defined as loadable modules.

This chapter describes how form data schemas are linked to the logic tier. It introduces a data description language (DDL) called simpleform that allows you to specify data schemas with the validation and normalization of atomic types. It also describes the Wolframe module concept for form descriptions that allows you to add a compiler for your existing data schemas.

After reading this chapter you should be able to write data forms of Wolframe of the logic tier in the simpleform data description language on your own. You should also know how a new data description language (DDL) could be added.

Be aware that you have to configure a data description language type (DDL compiler) of the logic tier in Wolframe before using it. Each chapter introducing a data form description language will have a section that describes how the server configuration of Wolframe has to be extended for its availability.

5.5.1. Form data definition languages

Introduction

Form data structures can be defined in a DDL (Data Definition Language). It depends very much on the application what DDL is best to use. Users may already have their data definitions defined in a certain way. The form DDL can be defined in the way you want. Wolframe offers a plugin mechanism for DDL compilers and provides examples of such compilers. You configure the DDL sources to load and the compiler to use.

With the DDL form description we get a deserialization of some content into a structure and a serialization for the output. We get also a validation and normalization procedure of the content by assigning types to atomic form elements that validate and normalize the data elements. Most of the business transactions should be doable as input form description, output form description and a transaction that maps input to output without control flow aware programming.

All types of data forms introduced here are equivalent in use for all programs.

Forms in simpleform DDL

As example of a form DDL we provide the simpleform DDL. In simple form we forms, subtructures for reuse inside structures and forms and includes that help you to organize your code.

Commands

The simpleform language has 3 commands:

FORMDeclare the name of the form, some document meta data and the structure that represents the description of the document content of this form
STRUCTDeclare the name of the structure, the structure that can be referenced by name in structures of subsequent FORM or STRUCT declarations
INCLUDEinclude the file given as argument

Structures

Structures in FORM or STRUCT declarations are defined as list of elements in curly brackets '{' '}'.

The following example shows an empty structure declaration

STRUCT myStructure
{
}
	

The following example shows an empty form declaration

FORM myDocumentSchema
{
}
	

Elements of structures

An element in the list is either a declaration of a substructure or an atomic element. The elements are separated by comma ',' or end of line.

The following example shows a structure that is a list with 3 elements separated by end of line

{
    number int
    name string
    id int
}
		

And the same example with a comma as element separator

{
    number int, name string, id int
}
		

An element starts with an identifier, the name of the element. The name is followed by some special characters defining the element attributes and the element type. The element attributes will be described later. The element type is either an embedded substructure in '{' '}' brackets or an identifier naming an atomic type or a substructure declared previously as a STRUCT.

Embedded structure definitions

Here is an example with a embedded substructure

{
    number int
    name string
    address {
        street string, country string
    }
}
		

Embedded substructure declarations follow recursively the same rules as structures defined here.

Default atomic value assignments

Named types referencing atomic types can be followed by an assignment operator '=' and a string that declared a default value initialization of the structure element. Here is an example with a default value assignment

{
    number int = 1
    name string
}
		

Types of atomic values

The atomic element type names are either the reserved keyword string or a type defined as sequence of normalizer functions in a normalize definition file. The normalizer functions assigned to a type validate the value and transform it to its normalized form. The next section will explain how data types are defined.

Element attributes

The element attributes are marked with some special characters listed and explained in the following table:

Table 5.15. Element attributes in simpleform

 LocationExampleDescription
@prefix of data typeid @intExpresses that the element is an attribute and not a content element of the structure. This has only influence on the XML or similar representation of the form content
?prefix of data typevalue ?stringExpresses that the element is optional also in strict validation
^prefix of form nameltree ^bintreeExpresses that the element is optional and refers to a structure defined in the same module that is expanded only if the element is present. With this construct it is possible to define recursive structures like trees.
!prefix of data typeid !intExpresses that the element is always mandatory (also in non strict validation)
[]suffix of data typevalues string[]Expresses that the element is an array of this type
[]without data typear [] { }Expresses this element is an array of structures and that the structure defined describes the prototype (initialization) element of the array.
='..'end of data type declarationid int = 1Expresses that '..' is the default initialization value of this element.


Non contradicting attributes can be combined:

id ?@int = 1
		

Embedding elements and inheritance

Using a single underscore '_' as atomic element name means that the atomic element is representing the unnamed content value of the structure. Using a single underscore for a substructure means that the substructure is embedded into the structure without being referenceable by name. The embedding into a structure is used to express inheritance.

Here is an example with embedding of a named structure

STRUCT content
{
    name string
    birth string
}

FORM insertedContent
{
    id int
    _ content
}
		

Declaring document meta data

Document meta data in FORM definitions are declared after the form declaration header and before the form structure declaration. A meta data declaration starts with a dash '-' followed by the meta data attribute name as identifier or string and the value as string.

Here is an example of a form with meta data declarations

FORM myDoc
    -root = 'doc', -schemaLocation = 'http://bla.com/schema'
{
}
		

or with end of line as attribute separator

FORM myDoc
    -root = 'doc'
    -schemaLocation = 'http://bla.com/schema'
{
}
		

Example form definition

Now all elements of simpleform are explained. Here is an example that shows a complete form definition in simpleform DDL.

		
FORM Customer
	-root customer
{
    ID !@int                  ; Internal customer id (mandatory)
    name string               ; Name of the customer
    canonical_Name string     ; Customer name in canonical form
    country string            ; Country
    locality ?string          ; Locality (optional)
}

		

5.5.2. Datatypes in DDLs

Introduction

The basic elements to build atomic data types in Wolframe are normalization functions. Basic normalization functions are written in C++ and loadable as modules.

As we already mentioned are atomic elements in forms typed. With each type a function is associated to validate and normalize the atomic element of that type. There is only one predefined type called 'string'. strings are neither validated nor transformed for processing in any way. The others are defined in files with the extension .wnmp that are referenced as programs in the configuration.

A .wnmp file contains assignments of a type name to sequences of basic normalization function calls where the first takes the initial input. A normalization function call can either be a normalizer function or a custom data type defined in a module or a method of the predecessing custom data type in the sequence of the normalization function calls. The output of a function in the sequence gets the input of the next one and the final output for the last one. Each normalization step validates the input as atomic type (arithmetic,string,etc.) and transforms it to another atomic type.

Example

The example defines 3 numeric types including trimming of the input string for mode tolerant parsing and a string type that is converted to lowercase as normalization.

		
int=trim,integer(5);
uint=trim,unsigned;
currency=trim,fixedpoint( 13, 2);
name=trim,lcname;

		

Language description

Type assignments

Each type declaration in a .wnmp file starts with an identifier followed by an assignment operator '='. The left side identifier specifies the name of the type. This type name can be used in a DDL as name instead of the built-in type string. A token of this type is validated and normalized with the comma separated sequence of normalizer references on the right side of the assignment. A normalizer reference consists of an identifier plus an optional comma separated list of constant arguments in brackets ('(' and ')'). The interpretation of the arguments depend on the function type. An integer type for example could have the maximum number of digits of the integer type.

Standard modules for normalizers

There are some standard modules you can use when you define your own type system. They are delivered with Wolframe:

  • mod_normalize_locale: Unicode string composite normalization

  • mod_normalize_string: Basic string normalization (like trim, etc.)

  • mod_normalize_base64: Base64 encoding/decoding

  • mod_datatype_datetime: Custom data type for date and time arithmetics and normalization

  • mod_datatype_bcdnumber: Custom data type for bid number arithmetics and normalization

Configuration

For declaring and using a .wnmp file in our example above, we have to load the module 'mod_normalize_string' and the module 'mod_normalize_number'. For this we add the following two lines to the LoadModules section of our Wolframe configuration:

		
    Module mod_normalize_number
    Module mod_normalize_string


		

We also have to add the declaration of the program "example.wnmp" (listing example above) to the Processor section of the configuration.

	
    Program example.wnmp