Mapping

Mapping is a part of each transformation defined in some of the CloudConnect components.

Calculated or generated values or values of input fields are assigned (mapped) to output fields.

  1. Mapping assigns a value to an output field.

  2. Mapping operator is the following:

    :=

  3. Mapping must always be defined inside a function.

  4. Mapping must be defined at the end of the function and may only be followed by one return statement.

  5. Remember that you can also wrap a mapping in a user-defined function which would be subsequently used in any place of another function.

  6. You can also map different input metadata to different output metadata by field names.

Mapping of Different Metadata (by Name)

When you map input to output like this:

$0.* := $0.*;

input metadata may even differ from those on the output.

In the expression above, fields of the input are mapped to the fields of the output that have the same name and type as those of the input. The order in which they are contained in respective metadata and the number of all fields in either metadata is of no importance.

Example 61.3. Mapping of Metadata by Name

When you have input metadata in which the first two fields are firstname and lastname, each of these two fields is mapped to its counterpart on the output. Such output firstname field may even be the fifth and lastname field be the third, but those two fields of the input will be mapped to these two output fields .

Even if input metadata had more fields and output metadata had more fields, such fields would not be mapped to each other if there did not exist a field with the same name as one of the input fields (independently on the mutual position of the fields in corresponding metadata).


[Important]Important

Metadata fields are mapped from input to output by name and data type independently on their order and on the number of all fields!

Use Case 1 - One String Field to Upper Case

To show how mapping works, we provide here a few examples of mappings.

We have a graph with a Reformat component. Metadata on its input and output are identical. First two fields (field1 and field2) are of string data type, the third (field3) is of integer data type.

  1. We want to change the letters of field1 values to upper case while passing the other two fields unchanged to the output.

  2. We also want to distribute records according to the value of field3. Those records in which the value of field3 is less than 5 should be sent to the output port 0, the others to the output port 1.

Examples of Mapping

As the first possibility, we have the mapping for both ports and all fields defined inside the transform() function of CTL template.

Example 61.4. Example of Mapping with Individual Fields

The mapping must be defined at the end of a function (the transform() function, in this case) and it may only be followed by one return statement.

Since we need that the return statement return the number of output port for each record, we must assign it the corresponding value before the mapping is defined.

Note that the mappings will be performed for all records. In other words, even when the record will go to the output port 1, also the mapping for output port 0 will be performed, and vice versa.

Moreover, mapping consists of individual fields, which may be complicated in case there are many fields in a record. In the next examples, we will see how this can be solved in a better way.

//#TL
          
// declare variable for returned value (number of output port) 
int retInt;

function transform() {	
     // create returned value whose meaning is the number of output port.
     if ($0.field3 < 5) retInt = 0; else retInt = 1;

     // define mapping for all ports and for each field 
     // (each field is mapped separately)
     $0.field1 := uppercase($0.field1);
     $0.field2 := $0.field2;
     $0.field3 := $0.field3;	
     $1.field1 := uppercase($0.field1);	
     $1.field2 := $0.field2;
     $1.field3 := $0.field3;	

     // return the number of output port
     return retInt
}

As the second possibility, we also have the mapping for both ports and all fields defined inside the transform() function of CTL template. But now there are wild cards used in the mapping. These passes the records unchanged to the outputs and after this wildcard mapping the fields that should be changed are specified.

Example 61.5. Example of Mapping with Wild Cards

The mapping must also be defined at the end of a function (the transform() function, in this case) and it may only be followed by one return statement.

Since we need that return statement returns the number of output port for each record, we must assign it the corresponding value before the mapping is defined.

Note that mappings will be performed for all records. In other words, even when the record will go to the output port 1, also the mapping for output port 0 will be performed, and vice versa.

However, now the mapping uses wild cards at first, which passes the records unchanged to the output, but the first field is changed below the mapping with wild cards.

This is useful when there are many unchanged fields and a few that will be changed.

//#TL
          
// declare variable for returned value (number of output port) 
int retInt;

function transform() {	
     // create returned value whose meaning is the number of output port.
     if ($0.field3 < 5) retInt = 0; else retInt = 1;

     // define mapping for all ports and for each field 
     // (using wild cards and overwriting one selected field)	
     $0.* := $0.*;
     $0.field1 := uppercase($0.field1);
     $1.* := $0.*;
     $1.field1 := uppercase($0.field1);	

     // return the number of output port
     return retInt
}

As the third possibility, we have the mapping for both ports and all fields defined outside the transform() function of CTL template. Each output port has its own mapping.

Also here, wild cards are used.

The mapping that is defined in separate function for each output port allows the following improvements:

  1. Mappings may now be used inside the code in the transform() function! Not only at its end.

  2. Mapping is performed only for respective output port! In other words, now there is no need to map record to the port 1 when it will go to the port 0, and vice versa.

  3. And, there is no need of a variable for the number of output port. Number of output port is defined by constants immediately after corresponding mapping function.

Example 61.6. Example of Mapping with Wild Cards in Separate User-Defined Functions

The mappings must be defined at the end of a function (two separate functions, by one for each output port).

Moreover, mapping uses wild cards at first, which passes the records unchanged to the output, but the first field is changed below the mapping with wild card. This is of use when there are many unchanged fields and a few that will be changed.

//#TL
          
// define mapping for each port and for each field 
// (using wild cards and overwriting one selected field) 
// inside separate functions
function mapToPort0 () { 
     $0.* := $0.*;
     $0.field1 := uppercase($0.field1);
}

function mapToPort1 () { 
     $1.* := $0.*;
     $1.field1 := uppercase($0.field1);
}

// use mapping functions for all ports in the if statement
function transform() {
     if ($0.field3 < 5) { 
          mapToPort0(); 
          return 0
     }
     else {
          mapToPort1();
          return 1
     }
}

Use Case 2 - Two String Fields to Upper Case

We have a graph with a Reformat component. Metadata on its input and output are identical. First two fields (field1 and field2) are of string data type, the third (field3) is of integer data type.

  1. We want to change the letters of both the field1 and the field2 values to upper case while passing the last field (field3) unchanged to the output.

  2. We also want to distribute records according to the value of field3. Those records in which the value of field3 is less than 5 should be sent to the output port 0, the others to the output port 1.

Example 61.7. Example of Successive Mapping in Separate User-Defined Functions

Mapping is defined in two separate user-defined functions. The first of them maps the first input field to both output ports. The second maps the other fields to both output fields.

Note that these functions now accept one input parameter of string data type - valueString.

In the transformation, a CTL record varibale is declared. Input record is mapped to it and the record is used in the foreach loop.

Remember that the number of output port is defined in the if that follows the code with the mapping functions.

//#TL
          
string myString;
string newString;
string valueString;

// declare the count variable for counting string fields
int count;

// declare CTL record for the foreach loop
record (@0) CTLRecord;

// declare mapping for field 1
function mappingOfField1 (valueString) { 
     $0.field1 := valueString;
     $1.field1 := valueString;
}

// declare mapping for field 2 and 3
function mappingOfField2and3 (valueString) { 
     $0.field2 := valueString;
     $1.field2 := valueString;
     $0.field3 := $0.field3;
     $1.field3 := $0.field3;
}

function transform() {

     // count is initialized for each record
     count = 0;

     // input record is assigned to CTL record
     CTLRecord = @0;

     // value of each string field is changed to upper case letters
     foreach (myString : CTLRecord) {
          newString = uppercase(myString);
          // count variable counts the string fields in the record
          count++;

          // mapping is used for fields 1 and the other fields - 2 and 3
          switch (count) {
               case 1 : mappingOfField1(newString); 
               case 2 : mappingOfField2and3(newString); 
          }
     }

     // output port is selected based on the return value
     if($0.field3 < 5) return 0 else return 1
}