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.
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.
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.
The simpleform language has 3 commands:
FORM | Declare the name of the form, some document meta data and the structure that represents the description of the document content of this form |
STRUCT | Declare the name of the structure, the structure that can be referenced by name in structures of subsequent FORM or STRUCT declarations |
INCLUDE | include the file given as argument |
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 { }
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
.
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.
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 }
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.
The element attributes are marked with some special characters listed and explained in the following table:
Table 5.15. Element attributes in simpleform
Location | Example | Description | |
---|---|---|---|
@ | prefix of data type | id @int | Expresses 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 type | value ?string | Expresses that the element is optional also in strict validation |
^ | prefix of form name | ltree ^bintree | Expresses 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 type | id !int | Expresses that the element is always mandatory (also in non strict validation) |
[] | suffix of data type | values string[] | Expresses that the element is an array of this type |
[] | without data type | ar [] { } | 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 declaration | id int = 1 | Expresses that '..' is the default initialization value of this element. |
Non contradicting attributes can be combined:
id ?@int = 1
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 }
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' { }
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) }
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.
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;
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.
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
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
Copyright © 2014 - Project Wolframe - All Rights Reserved