Architecture - Available transformation functions

From wiki.gpii
Jump to: navigation, search

Contents

Introduction to transformations

The model transformation framework is part of Fluid Infusion and allows you to change an input model (JSON structure) based on a set of rules. The result will be a new JSON structure, built according to the rules specified and the input model.

As an example, imagine that you have a set of preferences specified in some format that is usable for application A and want to transform those into settings that are understandable by some other application B. To do this you would specify a set of rules, describing how the settings should be transformed from application A so it can be used by application B. More concretely

imagine you have the following 'input model - settings defined in a way that application A understands them':

{
    "display": {
        "magnification": 0.8919,
        "invert": true
    }
}

And a set of transformation rules, describing how to translate these settings into something compatible with application B:

{
    "Magnification": {
        "dataType": {
            "literalValue": "REG_DWORD"
        },
        "value": {
            "transform": {
                "type": "fluid.transforms.round",
                "input": {
                    "transform": {
                        "type": "fluid.transforms.linearScale",
                        "valuePath": "display.magnification",
                        "factor": 100
                    }
                }
            }
        }
    }
}

Running the above transformation rules on the input model will result in the output document:

{
    "Magnification": {
        "dataType": "REG_DWORD"
        "value": 89
    }
}

In the below, the mechanics of the rules, detailed description of each of the transformations, and how the output document is created will be explained. The important thing to understand now is that the the model transformation system allows you to create an output document with some desired structure based on some input (the input model) and a set of rules (transformation rules). In common usage, your rules are likely to be a statically defined document, that can get applied to different input documents (with the same structure). So in the above example, we might have a different person with a different preference set (input model):

{
    display: {
        magnification: 1,
    }
}

which, when run through the same transformation rules would result in different output document, namely:

{
    Magnification: {
        dataType: "REG_DWORD"
        value: 100
    }
}

Building the output structure

The ultimate goal when using the model transformation is to create an output document with some desired structure (and based on information in some input document). Therefore it's important to know how to build the output structure of the document. There are different ways of writing, and these will be explained below.

Strings as keys

The simplest and most natural way to create the output structure is by using strings as keys in your output document. Returning to the rules set used in the previous section:

{
    "Magnification": {
        "dataType": {
            "literalValue": "REG_DWORD"
        },
        "value": {
            "transform": {
                "type": "fluid.transforms.round",
                "input": {
                    "transform": {
                        "type": "fluid.transforms.linearScale",
                        "valuePath": "display.magnification",
                        "factor": 100
                    }
                }
            }
        }
    }
}

Here, the string output structure is defined using strings as keys, like "Magnification", "dataType" and "value". Whenever the transformation system encounters a key, that is a non-reserved word, and that is not inside a "transform" block, it will consider that a change in the output path / output structure. So the walking through the above rules, the first thing we encounter is "Magnification". Since this is not a reserved word, the system will ensure that everything within that block gets outputted relative to an output path "Magnification". The same goes for "dataType" - everything inside here will be output relative to the path "dataType" (which in turn is relative to Magnification, giving us the output path: "magnification.dataType"). "literalValue" inside dataType is a reserved word, so instead of interpreting this as a change to the output structure, it will be resolved by the model transformation system - a "literalValue" key, is a way to tell the system to literally print the value to the current output path, which as described above is at this location "Magnification.dataType".

Like with 'dataType', the "value" key under Magnification means that we change the output path for anything in that block. "transform" is a keywork, so this does not affect the output path. Nor do the keys directly in a "transform" block, meaning that "type" and "input" will not affect the output path. The same holds for the next transform blocks. This means that whatever the result of the rules inside the "value" block is, will get output to "Magnification.value" path.

Repeating the example above, an input model of:

{
    "display": {
        "magnification": 0.5,
        "invert": true
    }
}

Running through the transformation will result in the following output document:

{
    "Magnification": {
        "dataType": "REG_DWORD"
        "value": 50
    }
}

Reserved words

In general, the reserved words of the system (those that will not be interpreted as a change in output path) are:

  • "transform"
  • "literalValue"

Some transformations have further reserved words. These will be described for each relevant transformation.

Explictly outputting to a (relative) path

An alternative way to specifying where you want to output values is by using the "outputPath" key. The value of outputPath defines the location where you want to ouput the result of the transform. "outputPath" can only be specfied in a transform block (ie. at the same level as the "type" specification for the transform). "outputPath" works for most transformations (namely any standard output transformation (see section TODO)).

Returning to the rule set above, this could be rewritten as

{
    "transform": [
        {
            "type": "fluid.transforms.literalValue",
            "input": "REG_DWORD",
            "outputPath": "Magnification.dataType"
        }, {
            "type": "fluid.transforms.round",
            "input": {
                "transform": {
                    "type": "fluid.transforms.linearScale",
                    "valuePath": "display.magnification",
                    "factor": 100
                }
            },
            "outputPath": "Magnification.value"
        }
    ]
}

Here, the "literalValue" transformation specifies that the result should be output to the path "Magnification.dataType". Same for the "fluid.transforms.round" transform, where the output will be sent to the path "Magnification.value". Like with the above, the input model:

{
    "display": {
        "magnification": 0.5,
        "invert": true
    }
}

Running through these rules will result in the following output document:

{
    "Magnification": {
        "dataType": "REG_DWORD"
        "value": 50
    }
}

It should be noted that the "outputPath" will be relative to the current output path specified via a string as key. So we could rewrite the above rule to:

{
    "Magnification": {
        "transform": [
            {
                "type": "fluid.transforms.literalValue",
                "input": "REG_DWORD",
                "outputPath": "dataType"
            }, {
                "type": "fluid.transforms.round",
                "input": {
                    "transform": {
                        "type": "fluid.transforms.linearScale",
                        "valuePath": "display.magnification",
                        "factor": 100
                    }
                },
                "outputPath": "value"
            }
        ]
    }
}

and we would get the same result. That is, for example the "outputPath": "dataType", would be relative to the "Magnification" path, and hence result in the path "Magnification.dataType"

Return values, Arrays of transforms and arrays in transforms

Return values

In general, transformations pass their result one level up, unless "outputPath" is explicitly given. This is the reason that something like the below works:

{
    "transform": {
        "type": "fluid.transforms.round",
        "input": {
            "transform": {
                "type": "fluid.transforms.linearScale",
                "valuePath": "display.magnification",
                "factor": 100
            }
        },
        "outputPath": "Magnification.value"
    }
}

Here the result of the inner "fluid.transforms.linearScale" transform is passed to the "fluid.transforms.round" transform, which in turns outputs it to the "outputPath". Whenever an "outputPath" is specified, the result is output to the document instead, and hence not returned to the parent transform function (if any). Generally, this behavior should be rather intuitive.

Arrays of transforms

Things get slighly more complicated when we introduce arrays of transforms, like in the examples from the previous section. Whenever you specify an array of transforms (ie. "transforms": [ (...) ]), nothing will get returned to the outer transform. The consequence of this is that if you have arrays of transforms, you are required to explicitly output values via "outputPath". Take the following rules, for example:

{
    "Magnification": {
        "transform": [
            {
                "type": "fluid.transforms.literalValue",
                "input": "REG_DWORD",
                "outputPath": "dataType"
            }, {
                "type": "fluid.transforms.round",
                "input": {
                    "transform": {
                        "type": "fluid.transforms.linearScale",
                        "valuePath": "display.magnification",
                        "factor": 100
                    }
                },
                "outputPath": "value"
            }
        ]
    }
}

This works because we have specified the "outputPath" for both transforms. If we had omitted these, nothing would be output to the document.

Arrays in transforms

Outputting an array in the document is very straight forward, one simply specifies it, as one would normally in javascript/json - using []. The array will be populated with the results of the content as one would expect as well. If one of the array entries has a result of undefined (eg. due to an inputPath referencing something non-existant in input model -- see below), this would also populate a spot in the array - to ensure that indexes of results are consistent.

As an example, take the following set of rules

{
    "my_pets": [
        {
            "transform": {
                "type": "fluid.transforms.literalValue",
                "inputPath": "petlist.cat"
            }
        }, {
            "transform": {
                "type": "fluid.transforms.literalValue",
                "inputPath": "petlist.goldfish"
            }
        }, {
            "transform": {
                "type": "fluid.transforms.literalValue",
                "inputPath": "petlist.frog"
            }
        }
    ]
}

Running this transformation with the following input model:

{
    "petlist": {
        "cat": "Kaspar the Titanic Cat",
        "frog": "Portuguese Steve"
    }
}

Would give the following result:

{
    "my_pets": [
        "Kaspar the Titanic Cat",
        undefined,
        "Portuguese Steve"
    ]
}

Notice the undefined value. This is the result of the second transform (since no value was found at the "petlist.goldfish" input path, undefined is returned - this will be explained in the following section).

Static value vs. reading from input model

For a lot of transformations, there are two ways of providing inputs to be interpreted by the rules. One way is to pass a staic value, given directly in the rules document. This means that the result of the transformation in question will be the same every time. Alternatively, once can use inputs from the input document, by referencing the path where the value to be used can be found. When doing this, the result of the transformation will vary depending on the input document provided to the transformation. It is of course possible to use the two types of inputs in the rules

Static value

As mentioned above, you can defined static values to the transformers by typing the values directly into the rules. For example:

{
    "my_pet": {
        "transform": {
            "type": "fluid.transforms.literalValue",
            "input": "Kaspar the Titanic Cat"
        }
    }
}

The result of this rule will be:

{
    "my_pet": "Kaspar the Titanic Cat"
}

regardless of the input model supplied to the transformation. Every time the transformation is run, the result will be the same.

Reading inputs from input model

Obviously, to make model transformations useful, one needs to be able to get a different output document depending on the input document supplied to the transformations. One can read from the input paths by supplying it as the arguments to transformations.

For example, the below literalValue transformation gets its input from the path "petlist.cat" in the input model:

{
    "my_pet": {
        "transform": {
            "type": "fluid.transforms.literalValue",
            "inputPath": "petlist.cat"
        }
    }
}

Given an input model of:

{
    "petlist": {
        "cat": "Kaspar the Titanic Cat"
    }
}

The result of the transformation would be

{
    "my_pet": "Kaspar the Titanic Cat"
}

So here, the literal value is taken from the input model. If one was to run the transformation a second time, with a different input model, say:

{
    "petlist": {
        "cat": "CATTOO"
    }
}

The result of the transformation would instead be

{
    "my_pet": "CATTOO"
}

If no value is found in the given path, undefined will be returned from the transformation. So if we have an input model without the path "petlist.cat", like:

{
    "petlist": {
        "dog": "Spot"
    }
}

The result of the literalValue transformation would be undefined, and one would recieve an empty output document.


Using static values as default fallback value

As mentioned, it is possible to use both types of inputs in your ruleset in the different transforms, but it is also possible to specify both for a given transformation. The effect of this, is that the input from the model (via path) will be used if it is found, else the static value will be used. This is useful if you want to supply the system with a default value. Take for example the following rules:

{
    "my_pet": {
        "transform": {
            "type": "fluid.transforms.literalValue",
            "inputPath": "petlist.cat",
            "input": "I have no cat"
        }
    }
}

If we did the transformation with the following input model:

{
    "petlist": {
        "cat": "Kaspar the Titanic Cat"
    }
}

The result of would be

{
    "my_pet": "Kaspar the Titanic Cat"
}

as this is what's read from the "petlist.cat" path. On the other hand, if we supplied it with the following model:

{
    "petlist": { }
}

the system would fail at finding any value at "petlist.cat", and instead use the value supplied via input, resulting in the output document:

{
    "my_pet": "I have no cat"
}


Grades of transformations

Transformation can be registered with different grades (or classes), which define how they handle inputs and outputs. The standard base grades recognised by the framework as as follows:

standardInputTransformFunction:

These transformations takes an input which can be defined in two ways:

  • input: As a constant defined in the transform using the key input
  • inputPath: As a path reference to the input (model) by using the key inputPath.

If both keys are used in an transform declaration, the value found at the inputPath will be used if something is found there. If not, the transformer will default to using the value defined by value. Besides this input, the transformation might require an arbitrary number of constants given in the transform declaration.

standardOutputTransformFunction:

These transformations only outputs a single value. The value of the output depends on the transformation, but the path to output to can be defined by:

  • outputPath: An EL path to where the transformation should output it's value to.

In case the transform is nested within other transforms (eg. a valuemapper), the outputPath specified will be relative to the outputPaths specified in the outer levels as well as to the location of the outermost transform.

standardTransformFunction:

These transformations satisfy the requirements of both standardInputTransformFunction and standardOutputTransformFunction (see above)

multiInputTransformFunction:

These transformations allows for multiple inputs. In their default blocks, besides the gradename, they require an "inputVariables" key. The value of this should be a hash of key-value pairs, where the key is the variable name and the value is the default value to assign to the variable in case no matching constant or path is found. For each of the variables declared, the system will look up the source-model path defined by <variable>Path in the transform and the <variable> declared in the transform. The path takes priority. Example:

fluid.defaults("fluid.transforms.scaleValue", {
    gradeNames: [ "fluid.multiInputTransformFunction" ],
    inputVariables: { 
        value: null, 
        factor: 1,
        offset: 0
    }
});

The above declaration defines three input variables; value, factor and offset. Taking as an example the factor, the first thing that will be looked up in the transform is the value of "factorPath". If it is defined, this path will be looked up in the source-model and this will be assigned to factor if found. If it's not found, the value (expanded if necessary) of the "factor" key of the transform will be used if found. If neither is found, the default value of 1 will be assigned to factor.

The inputVariables will be available to fluid.transforms.scaleValue as the first argument in the form of an object keyed by variable names with the values as described above.

Transformers

Literal Value (fluid.transforms.literalValue)

Description: Returns the value given as input (or via inputPath), without attempting to do further transformations for that value. This transformation is basically an identity function - it will output the constant value given as input.

Type: standardTransformation Inputs:

  • input / inputPath 

Syntax:

transform: {
    type: "fluid.transforms.literalValue",
    input: <constant value>
}


Example 1: You can use literalValue if you have some constant that you want to output to the document

transform: {
    type: "fluid.transforms.literalValue",
    input: "some constant"
}

Output: The output in this case would be:

"some constant"

Example 2: The content of literal value will need be transformed further

transform: {
    type: "fluid.transforms.literalValue",
    input: {
       transform: {
          type: "fluid.transforms.helloworld",
          value: "I'm not interpreted"
       }
    }
}

Output: The content of value will just be output literally:

transform: {
    type: "fluid.transforms.helloworld",
    input: "I'm not interpreted"
}


Example 3: Like all transforms - will fall back from path to direct value

transform: {
    type: "fluid.transforms.literalValue",
    input: "balloon",
    inputPath: "some.path"
}

Output: if anything is found at the path "some.path" the content of that will be output literally, else "balloon" will be output.

Value from a Path (fluid.transforms.value)

Syntax:

transform: {
    "type": "fluid.transforms.value",
    "inputPath": "some.path"
}

Output: The value found at "some.path" will be output.

Shorthand version:

"value": "some.path"

Examples of Full Form and Shorthands

The following syntax examples would have the same effect:

capabilitiesTransformation: {
    "highContrastEnabled": {
        transform: {
            "type": "fluid.transforms.value",
            "inputPath": "display.screenEnhancement.-provisional-highContrastEnabled"
        }
    }
}
capabilitiesTransformation: {
    "highContrastEnabled": {
        "value": "display.screenEnhancement.-provisional-highContrastEnabled"
    }
}
capabilitiesTransformation: {
    "highContrastEnabled": "display.screenEnhancement.-provisional-highContrastEnabled"
}

To Array (fluid.transforms.arrayValue)

Description: This transformation will turn its value into an array if it's not already an array.

Type: standardTransformation

Inputs:

  • input / inputPath

Syntax:

 
transform: {
    type: "fluid.transforms.arrayValue",
    input: <constant value>
}

Example 1: Passing a single value will wrap it in an array

 
transform: {
    type: "fluid.transforms.arrayValue",
    input: "some constant"
}

output:

[ "some constant" ]

If the value had been an array already, it would just had been passed as is (so in the case - value: [ "some constant "] - we would have got the same output).

Count length of array (fluid.transforms.count)

Description: If the input is an array, the lenght of the array will be the output of this function. If the input is a primitive or object, 1 will be returned.

  • input / inputPath

Type: standardTransformation Inputs:

Syntax:

transform: {
    type: "fluid.transforms.count",
    value: <constant value>
}

Example 1:

 
transform: {
    type: "fluid.transforms.arrayValue",
    value: [ "foo", "bar" ]
}

output:

[ "foo" ]


Get first value of array (fluid.transforms.firstValue)

Description: Will return the first entry of an array that does not evaluate to undefined. The input is required to be of type array.

Type: fluid.transformFunction

Syntax:

transform: {
    type: "fluid.transforms.firstValue",
    values: <constant of array type>
}

Example 1:

transform: {
    type: "fluid.transforms.firstValue",
    values: [ undefined, "bar" ]
}

Output:

bar

Delete path from the output (fluid.transforms.delete)

Description: This transformation will delete a path from the output document. This is useful when outputting a large structure to the output document, but you require deletion of a certain part of that structure.

type: transformFunction

Syntax:

transform: {
    type: "fluid.transforms.delete",
    outputPath: <the output path to delete>
}

Example 1

{
    "": ""
    transform: {
        type: "fluid.transforms.delete",
        outputPath: foo
    }
}

Input model:

{ 
     hello: "world", 
     foo: "bar" 
}

Output:

{ 
     hello: "world"
}

The "": "" in the transform would normally mean that the entire input model is copied without any transformations, but the delete transform ensures that the path "foo" is deleted.

Binary operation (fluid.transforms.binaryOp)

type: multiInputTransformation (variables: left, right)

Syntax:

 
transform: {
    type: "fluid.transforms.binaryOp",
    left: <constant of appropriate type>,
    right: <constant of appropriate type>,
    operator: <the operator to use>
}

This will do a binary operation given the two operands (left and right) and the operator. You can reference to the input model for both left and right by using leftPath and rightPath. If both rightPath and right is given, a lookup will be done of rightPath first, and if nothing is found the constant from right will be used. Same goes for left and leftPath. Both the left and right operands are required (either in their path or constant form). The operator is also required. The result of the expansion will be the result of the binary operation. Valid operands are:

Arithmetic Operators (operands are required to be numbers, output will be a number):

  • +: (Addition) Adds 2 numbers.
  • -: (subtraction) As a unary operator, negates the value of its argument. As a binary operator, subtracts 2 numbers.
    • (Multiplication) Multiplies 2 numbers.
  • /: (Division) Divides 2 numbers.
  •  %: (Modulus) Computes the integer remainder of dividing 2 numbers.

Comparison Operators: (operands are required to be numbers, output will be boolean)

  • ===: Returns true if the operands are equal.
  •  !==: Returns true if the operands are not equal.
  • >: Returns true if left operand is greater than right operand.
  • >=: Returns true if left operand is greater than or equal to right operand.
  • <: Returns true if left operand is less than right operand.
  • <=: Returns true if left operand is less than or equal to right operand.

Logical Operators: (both operands are required to be booleans, output will be boolean)

  • &&: (Logical AND) Returns true if both logical operands are true. Otherwise, returns false.
  • ||: (Logical OR) Returns true if either logical expression is true. If both are false, returns false.

Example:

 
transform: {
    type: "fluid.transforms.binaryOp",
    left: 100,
    rightPath: "some.path",
    operator: "+"
}

The above would give the sum (a number) of 100 and the value found in the input model at the path "some.path".

Conditional transform (fluid.transforms.condition)

type: multiInputTransformation (variables: true, false, condition)

Syntax:

 
transform: {
    type: "fluid.transforms.condition",
    condition: <boolean value>
    "true": <can be declared in the transform as variable or path - optional>,
    "false": <can be declared in the transform as variable or path - optional>
}

Based on the boolean condition constant (or the path to the inputModel conditionPath) either the value or true or false (truePath/falsePath, respectively) will be the result of the transform. The condition is required and either true or false (or both) - or their path equivalents - should be set.

Example:

 
transform: {
    type: "fluid.transforms.condition",
    conditionPath: "some.path",
    "true": "It was true",
    "false": "It was false"
}

Scale value with optional offset (fluid.transforms.linearScale)

Description: This will scale the input value using the equation: value * factor + offset. If factor is unspecified it will be interpreted as 1 and if offset is unspecified it will be interpreted as 0. Both factor and offset can references to the input model by using: factorPath and offsetPath, respectively. If both the path and constant for any of these values is defined, first the path is looked up, and if a value is found it will be used. Else the constant will be used. 

type: multiInputTransformation (variables: value, factor - default=1, offset - default=0)

Syntax:

transform: {
    type: "fluid.transforms.linearScale",
    value: <constant of array type>,
    factor: <the scaling factor>,
    offset: <the offset to use for the scaling>
}


Example 1: all variable specified

Rules:

transform: {
    type: "fluid.transforms.linearScale",
    value: 12,
    factor: 10,
    offset: 100
}

Output:

230

Example 2: Only some variables specified Rules:

transform: {
    type: "fluid.transforms.linearScale",
    value: 12,
    factorPath: "some.path"
}

Input Model:

{
    hello: "say what?"
}

Result:

12

In this example, if no value is found at some.path, the factor will default to 1, outputting 12*1+0=12. If a value was instead found (say, 12) the output would've been 12*12+0=144

Mapping a continuous range into discrete values (gpii.transformer.quantize)

Description: If you have a continuous range of values (eg. 0...*) and want to change that into discrete values, this is the transform you want. It also works as a non-linear scale of values, as you can define what ranges maps to what outputs.

The transform allows you to specify some ranges, defined by an upperBound. The first entry, the range will be the upperBound value to negative infinite. For the second entry, the range will be the range from the upperBound to (and excluding) the previous entry's upperBound. For the final entry no upper bound can be given, indicating that this range is from the previous upperBound to infinity.

type: standardTransformFunction

Syntax:

"transform": {
    "type": "gpii.transformer.quantize",
    "inputPath": <path to the value to check ranges from>,
    "ranges": [
        {
            "upperBound": <the upper bound for first entry, lower bound is infinity>,
            "output": <output value (or transform) in case the input falls into this range>
        }, {
            "upperBound": <the upper bound for second entry, lower bound is the 'upperBound' value from first entry>,
            "output": <output value (or transform) in case the input falls into this range>
        }, {
            (...)
        }, {
            "output": <output value (or transform) if input is between previous upper bound and infinity>
        }
    ]
}

Example 1: Usage of quantize transformer

Rules:

transform: {
    "type": "gpii.transformer.quantize",
    "inputPath": "my.input",
    "ranges": [
        {
            "upperBound": 11,
            "output": "small"
        }, {
            "upperBound": 13,
            "output": "normal"
        }, {
            "upperBound": 17,
            "output": "big"
        }, {
            "output": "very big"
        }
    ]
}

Input Model:

{
    hello: "12"
}

result:

"normal"

The output here would be "normal", as 12 is larger than the upper bound of the first entry (11) but smaller than the upper bound of the second entry (13)... Other examples would be: Input 2 -> Output "small" Input 20 -> Output "very big" input 16 -> Output "big" Input 17 -> Output "big"

Changing an object into an array (fluid.transforms.objectToArray)

Changing an array into an object (fluid.transforms.arrayToObject)

Syntax:

transform: {
    type: "fluid.transforms.arrayToObject",
    inputPath: "some input path pointing to an array",
    key: "the variable from array to use as key"
    innerValue: [ (...inner transforms...) ]
}

As the name suggests, the arrayToObject transform changes an array into an object. This can be useful to be able to refer to a certain EL path of an input by a key which unlike reference to an array index does not depend on the order of the array. The transform requires a key - one that is present in each of the array-entries and unique - this will be used to key the resulting object. For example:

If we have the input model:

foo: {
    bar: [ 
        { product: "salad", price: 10, healthy: "yes" },
        { product: "candy", price: 18, healthy: "no" }
    ]
}

And the transform

{
    transform: {
        type: "fluid.transforms.arrayToObject",
        inputPath: "foo.bar",
        key: "product"
    }
}

We are saying that we want the array found on inputPath and return an object where where the key will be the value of product and the content will be the remainder of the array entry. So the above would return:

{
    salad: { price: 10, healthy: "yes" },
    candy: { price: 18, healthy: "no" }
}

An optional variable to the transform is the "innerValue". Any variable or transform that needs to refer to the content of the array should be declared here. The input paths within the innerValue block will be relative to the original array entry. (This behavior will be changed later with FLUID-XYZ).

As an example:

foo: {
    bar: [ 
        { product: "salad", info: { price: 10, healthy: "yes" }},
        { product: "candy", info: { price: 18, healthy: "no", tasty: "yes" }}
    ]
}

And the transform

{
    transform: {
        type: "fluid.transforms.arrayToObject",
        inputPath: "foo.bar",
        key: "product",
        innerValue: [{
            transform: {
                type: "fluid.transforms.value",
                inputPath: "info.healthy",
            }

        }]
    }
}

In the second (innermost) inputPath, we refer to info.healthy, which is relative to the path defined by our outer inputPath.

{
    salad: "yes",
    candy: "no"
}

Changing an array to a set (fluid.transforms.setMembershipToArray)

Changing an array to a set (fluid.transforms.arrayToSetMembership)

Syntax:

transform: {
    type: "fluid.transforms.arrayToOutputs",
    inputPath: "some input path pointing to an array",
    presentValue: "The value that the entry in the set should have if present in array",
    missingValue: "That value that the entry should have if not present in the array",
    options: {
        "expectedArrayEntry1": "Key of set1",
        (...)
        "expectedArrayEntryN": "Key of setN",
    }
}

This transform can be used when one wants to create a set based on values available in an array. TODO: Add example and further descriptions. presentValue and missingValue are optional. If not defined, they'll default to true and false, respectively

Using the valueMapper to convert to/from enumerated sets of values

As the name suggests, the valueMapper allows you to build a map of values that can be used in converting enumerated values to other forms of enumerations, or to literal values.

Converting from one set of enumerated values to another

We might want to convert from one acceptable list of options to another, for example, when translating a font preference between two systems.

Syntax:

"transform": {
                "type": "fluid.transforms.valueMapper",
                "inputPath": "fontFace.genericFontFace",
                "options": {
                    "serif": "times",
                    "sans serif": "verdana",
                    "monospaced": "default",
                    "fantasy": "default",
                    "cursive": "default"
                }

Converting from enumerated values to literal values using the valueMapper

Syntax:

"transform": {
    "type": "fluid.transforms.valueMapper",
    "inputPath": "app1.volume",
    "options": {
        "high": {
            "outputValue": {
                "transform": {
                    "type": "fluid.transforms.literalValue",
                    "value": 80,
                    "outputPath": "path"
                }
            }
        },
        "medium": {
            "outputValue": {
                "transform": {
                    "type": "fluid.transforms.literalValue",
                    "value": 50,
                    "outputPath": "path"
                }
            }
        },
        "low": {
            "outputValue": {
                "transform": {
                    "type": "fluid.transforms.literalValue",
                    "value": 20,
                    "outputPath": "path"
                }
            }
        },
        "off": {
            "outputValue": {
                "transform": {
                    "type": "fluid.transforms.literalValue",
                    "value": 0,
                    "outputPath": "path"
                }
            }
        }
    }
}

This transform would be useful to convert values like "low", "medium", "high" into numeric values.

Wiki Categories