MapForce generally maps data in an intuitive way, but you may come across situations where the resulting output seems to have too many, or too few items. This topic is intended to help you avoid such mapping problems.
Generally, every connection between a source and target item means: for each source item, create one target item. If the source node contains simple content (for example, string or integer) and the target node accepts simple content, then MapForce copies the content to the target node and, if necessary, converts the data type.
This generally holds true for all connections, with the following exceptions:
|•||A target XML root element is always created once and only once. If you connect a sequence to it, only the contents of the element will be repeated, but not the root element itself, and the result might not be schema-valid. If attributes of the root element are also connected, the XML serialization will fail at runtime, so you should avoid connecting a sequence to the root element. If what you want to achieve is creating multiple output files, connect the sequence to the "File" node instead, via some function that generates file names.|
|•||Some nodes accept a single value, not a sequence (for example, XML attributes, database fields , and output components in user-defined functions).|
MapForce displays the structure of a schema, database, or EDI file as a hierarchy of mappable items in the component. Each of these nodes may have many instances (or none) in the instance file or database.
Example: If you look at the source component in PersonListByBranchOffice.mfd, there is only a single node first (under Contact). In the BranchOffices.xml instance file, there are multiple first nodes and Contact nodes having different content, under different Office parent nodes.
It depends on the current context (of the target node) which source nodes are actually selected and have their data copied, via the connector, to the target component/item.
This context is defined by the current target node and the connections to its ancestors:
|•||Initially the context contains only the source components, but no specific nodes. When evaluating the mapping, MapForce processes the target root node first (PersonList), then works down the hierarchy.|
|•||The connector to the target node is traced back to all source items directly or indirectly connected to it, even via functions that might exist between the two components. The source items and functions results are added to the context for this node.|
|•||For each new target node a new context is established, that initially contains all items of the parent node's context. Target sibling nodes are thus independent of each other, but have access to all source data of their parent nodes.|
Applied to the example mapping above (PersonListByBranchOffice.mfd):
|•||The connection from Office through the filter (Office) to PersonList defines a single office as the context for the whole target document (because PersonList is the root element of the target component). The office name is supplied by the input component, which has a default containing "Nanonull, Inc."|
|•||All connections/data to the descendants of the root element PersonList, are automatically affected by the filter condition, because the selected single office is in the context.|
|•||The connection from Contact to Person creates one target Person per Contact item of the source XML (general rule). For each Person one specific Contact is added to the context, from which the children of Person will be created.|
|•||The connector from first to First selects the first name of the current Contact and writes it to the target item First.|
Leaving out the connector from Contact to Person would create only one Person with multiple First, Last, and Detail nodes, which is not what we want here. In such situations, MapForce issues a warning and a suggestion to fix the problem: "You can try to connect Contact with Person to resolve":
MapForce displays the structure of a schema, database, or EDI file as a hierarchy of mappable items in the component.
Depending on the (target) context, each mappable item of a source component can represent:
|•||a single instance node of the assigned input file (or database)|
|•||a sequence of zero to multiple instance nodes of the input file (or database)|
If a sequence is connected to a target node, a loop is created to create as many target nodes as there are source nodes.
If a filter is placed between the sequence and target node, the bool condition is checked for each input node i.e. each item in the sequence. More exactly, a check is made to see if there is at least one bool in each sequence that evaluates to true. The priority context setting can influence the order of evaluation, see below.
As noted above, filter conditions automatically apply to all descendant nodes.
|Note:||If the source schema specifies that a specific node occurs exactly once, MapForce may remove the loop and take the first item only, which it knows must exist. This optimization can be disabled in the source Component Settings dialog box (check box "Enable input processing optimizations based on min/maxOccurs").|
Function inputs (of normal, non-sequence functions) work similar to target nodes: If a sequence is connected to such an input, a loop is created around the function call, so it will produce as many results as there are items in the sequence.
If a sequence is connected to more than one such function input, MapForce creates nested loops which will process the Cartesian product of all inputs. Usually this is not desired, so only one single sequence with multiple items should be connected to a function (and all other parameters bound to singular current items from parents or other components).
|Note:||If an empty sequence is connected to such a function (e.g. concat), you will get an empty sequence as result, which will produce no output nodes at all. If there is no result in your target output because there is no input data, you can use the “substitute-missing” function to insert a substitute value.|
Functions with sequence inputs are the only functions that can produce a result if the input sequence is empty:
|•||exists, not-exists and substitute-missing (also, is-not-null, is-null and substitute-null, which are aliases for the first three)|
|•||aggregate functions (sum, count, etc.)|
|•||regular user-defined functions that accept sequences (i.e. non-inlined functions)|
The sequence input to such functions is always evaluated independently of the current target node in the context of its ancestors. This also means that any filter or SQL-Where components connected to such functions, do not affect any other connections.
Usually, function parameters are evaluated from top to bottom, but its is possible to define one parameter to be evaluated before all others, using the priority context setting.
In functions connected to the bool input of filter conditions, the priority context affects not only the comparison function itself but also the evaluation of the filter, so it is possible to join together two source sequences (see CompletePO.mfd, CustomerNo and Number). See Priority Context node/item.
Overriding the context
Some aggregate functions have an optional “parent-context” input. If this input is not connected, it has no effect and the function is evaluated in the normal context for sequence inputs (that is, in the context of the target node's parent).
If the parent-context input is connected to a source node, the function is evaluated for each parent-context node and will produce a separate result for each occurrence. See also Overriding the Mapping Context.
Bringing multiple nodes of the same source component into the context
This is required in some special cases and can be done with Intermediate variables.
© 2019 Altova GmbH