/// <summary> /// Builds the decision table definition /// </summary> /// <returns>Table decision definition built</returns> /// <exception cref="DmnBuilderException">Throws <see cref="DmnBuilderException"/> when the definition has already been built</exception> /// <exception cref="DmnBuilderException">Throws <see cref="DmnBuilderException"/> when there is no input, no output or no rule defined in builder</exception> protected internal override IDmnDecision Build() { if (IsBuilt) { throw Logger.Error <DmnBuilderException>("Decision is already built"); } if (InputsInternal.Count < 1) { throw Logger.Error <DmnBuilderException>($"At least one input must be defined for decision table {Name}"); } if (OutputsInternal.Count < 1) { throw Logger.Error <DmnBuilderException>($"At least one output must be defined for decision table {Name}"); } if (RulesInternal.Count < 1) { throw Logger.Error <DmnBuilderException>($"At least one rule must be defined for decision table {Name}"); } //create var tableDecision = new DmnDecisionTable( Name, HitPolicy, Aggregation, InputsInternal.Select(i => i.GetResultOrBuild()).ToArray(), OutputsInternal.Select(o => o.GetResultOrBuild()).ToArray(), RulesInternal.Select(r => r.GetResultOrBuild()).ToArray(), RequiredInputs.Select(i => Variables[i].GetResultOrBuild()).ToArray(), RequiredDecisions.Select(d => Decisions[d].GetResultOrBuild()).ToArray()); ResultInternal = tableDecision; return(tableDecision); }
/// <summary> /// Validates the <paramref name="sourceTable"/> within the <see cref="DmnModel"/> /// and creates <see cref="DmnDecisionTable"/> /// </summary> /// <param name="sourceTable">Decision source parsed from XML</param> /// <param name="decisionName">Unique name of decision</param> /// <param name="requiredInputs">Inputs required by decision</param> /// <param name="requiredDecisions">Decisions, the decision table depends on</param> ///<exception cref="ArgumentNullException"><paramref name="sourceTable"/>, <paramref name="decisionName"/>, <paramref name="requiredInputs"/> or <paramref name="requiredDecisions"/> is null.</exception> ///<exception cref="ArgumentException"><paramref name="decisionName"/> is empty</exception> /// <exception cref="DmnParserException">No outputs for decision table</exception> /// <exception cref="DmnParserException">No inputs for decision table</exception> /// <exception cref="DmnParserException">Input variable for decision table not found</exception> /// <exception cref="DmnParserException">No rules for decision table</exception> /// <exception cref="DmnParserException">Number of rule input entries doesn't match the number of inputs for decision table</exception> /// <exception cref="DmnParserException">Number of rule output entries doesn't match the number of outputs for decision table</exception> protected DmnDecisionTable CreateDecisionTable( DecisionTable sourceTable, string decisionName, List <IDmnVariable> requiredInputs, List <IDmnDecision> requiredDecisions) { if (sourceTable == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(sourceTable)} is null"); } if (decisionName == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(decisionName)} is null"); } if (string.IsNullOrWhiteSpace(decisionName)) { throw Logger.Fatal <ArgumentException>($"{nameof(decisionName)} is empty"); } if (requiredInputs == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(requiredInputs)} is null"); } if (requiredDecisions == null) { throw Logger.Fatal <ArgumentNullException>($"{nameof(requiredDecisions)} is null"); } //prepare outputs if (sourceTable.Outputs == null || sourceTable.Outputs.Count < 1) { throw Logger.Fatal <DmnParserException>($"No outputs for decision table {decisionName}"); } var outputs = new List <DmnDecisionTableOutput>(); var outputIdx = 0; foreach (var sourceOutput in sourceTable.Outputs) { //Label, Name, Id var sourceVariableName = !string.IsNullOrWhiteSpace(sourceOutput.Label) ? sourceOutput.Label : !string.IsNullOrWhiteSpace(sourceOutput.Name) ? sourceOutput.Name : sourceOutput.Id; var variableName = DmnVariableDefinition.NormalizeVariableName(sourceVariableName); if (!Variables.TryGetValue(variableName, out var variable)) { //create variable variable = new DmnVariableDefinition(variableName); Variables.Add(variableName, variable); } variable.AddValueSetter($"Table Decision {decisionName}"); CheckAndUpdateVariableType(variable, sourceOutput.TypeRef); var allowedValues = sourceOutput.AllowedOutputValues?.Values; outputs.Add(new DmnDecisionTableOutput(outputIdx, variable, allowedValues)); outputIdx++; } //prepare inputs if (sourceTable.Inputs == null || sourceTable.Inputs.Count < 1) { throw Logger.Fatal <DmnParserException>($"No inputs for decision table {decisionName}"); } var inputs = new List <DmnDecisionTableInput>(); var inputIdx = 0; foreach (var sourceInput in sourceTable.Inputs) { //Expression or variable by Label, Id DmnVariableDefinition variable = null; string expression = null; if (string.IsNullOrWhiteSpace(sourceInput.InputExpression?.Text)) { var sourceVariableName = !string.IsNullOrWhiteSpace(sourceInput.Label) ? sourceInput.Label : sourceInput.Id; var variableName = DmnVariableDefinition.NormalizeVariableName(sourceVariableName); if (!Variables.TryGetValue(variableName, out variable)) { throw Logger.Fatal <DmnParserException>( $"Input variable {sourceVariableName} ({variableName}) for decision table {decisionName} not found"); } CheckAndUpdateVariableType(variable, sourceInput.InputExpression?.TypeRef); } else { expression = sourceInput.InputExpression.Text; } var allowedValues = sourceInput.AllowedInputValues?.Values; inputs.Add(new DmnDecisionTableInput(inputIdx, variable, expression, allowedValues)); inputIdx++; } //prepare rules if (sourceTable.Rules == null || sourceTable.Rules.Count < 1) { throw Logger.Fatal <DmnParserException>($"No rules for decision table {decisionName}"); } var rules = new List <DmnDecisionTableRule>(); var ruleIdx = 0; foreach (var sourceRule in sourceTable.Rules) { if (sourceRule.InputEntries == null || sourceRule.InputEntries.Count != inputs.Count) { throw Logger.Fatal <DmnParserException>($"Number of input entries doesn't match the number of inputs for decision table {decisionName}. Rule Id:{sourceRule.Id} "); } if (sourceRule.OutputEntries == null || sourceRule.OutputEntries.Count != outputs.Count) { throw Logger.Fatal <DmnParserException>($"Number of output entries doesn't match the number of outputs for decision table {decisionName}. Rule Id:{sourceRule.Id} "); } var ruleInputs = new List <DmnDecisionTableRuleInput>(); var ruleOutputs = new List <DmnDecisionTableRuleOutput>(); var ruleName = string.IsNullOrWhiteSpace(sourceRule.Label) ? sourceRule.Id : sourceRule.Label; //inputs var ruleInputIdx = 0; foreach (var sourceRuleInputEntry in sourceRule.InputEntries) { if (!string.IsNullOrWhiteSpace(sourceRuleInputEntry.Text) && sourceRuleInputEntry.Text != "-") //don't create rule inputs with no condition - can be also represented as single dash { var ruleInput = new DmnDecisionTableRuleInput(inputs[ruleInputIdx], sourceRuleInputEntry.Text); ruleInputs.Add(ruleInput); } ruleInputIdx++; } //outputs var ruleOutputIdx = 0; foreach (var sourceRuleOutputEntry in sourceRule.OutputEntries) { var ruleOutput = new DmnDecisionTableRuleOutput(outputs[ruleOutputIdx], sourceRuleOutputEntry.Text); ruleOutputs.Add(ruleOutput); ruleOutputIdx++; } rules.Add(new DmnDecisionTableRule(ruleIdx, ruleName, ruleInputs.ToArray(), ruleOutputs.ToArray(), sourceRule.Description)); ruleIdx++; } var decisionTable = new DmnDecisionTable( decisionName, sourceTable.HitPolicy, sourceTable.Aggregation, inputs.ToArray(), outputs.ToArray(), rules.ToArray(), requiredInputs, requiredDecisions); return(decisionTable); }