public static OperationOutcome ValidateFp(this Validator v, ElementDefinition definition, ScopedNavigator instance) { var outcome = new OperationOutcome(); if (!definition.Constraint.Any()) { return(outcome); } if (v.Settings.SkipConstraintValidation) { return(outcome); } var context = instance.AtResource ? instance : instance.Parent; foreach (var constraintElement in definition.Constraint) { bool success = false; try { var compiled = getExecutableConstraint(v, outcome, instance, constraintElement); success = compiled.Predicate(instance, new FhirEvaluationContext(context) { Resolver = callExternalResolver }); } catch (Exception e) { v.Trace(outcome, $"Evaluation of FhirPath for constraint '{constraintElement.Key}' failed: {e.Message}", Issue.PROFILE_ELEMENTDEF_INVALID_FHIRPATH_EXPRESSION, instance); } if (!success) { var text = "Instance failed constraint " + constraintElement.ConstraintDescription(); var issue = constraintElement.Severity == ElementDefinition.ConstraintSeverity.Error ? Issue.CONTENT_ELEMENT_FAILS_ERROR_CONSTRAINT : Issue.CONTENT_ELEMENT_FAILS_WARNING_CONSTRAINT; v.Trace(outcome, text, issue, instance); } } return(outcome); IElementNavigator callExternalResolver(string url) { OperationOutcome o = new OperationOutcome(); var result = v.ExternalReferenceResolutionNeeded(url, o, "dummy"); if (o.Success && result != null) { return(result); } return(null); } }
public static OperationOutcome ValidateFp(this Validator v, ElementDefinition definition, ScopedNode instance) { var outcome = new OperationOutcome(); if (!definition.Constraint.Any()) { return(outcome); } if (v.Settings.SkipConstraintValidation) { return(outcome); } var context = instance.ResourceContext; foreach (var constraintElement in definition.Constraint) { // 20190703 Issue 447 - rng-2 is incorrect in DSTU2 and STU3. EK // should be removed from STU3/R4 once we get the new normative version // of FP up, which could do comparisons between quantities. if (constraintElement.Key == "rng-2") { continue; } bool success = false; try { var compiled = getExecutableConstraint(v, outcome, instance, constraintElement); success = compiled.Predicate(instance, new FhirEvaluationContext(context) { ElementResolver = callExternalResolver }); } catch (Exception e) { v.Trace(outcome, $"Evaluation of FhirPath for constraint '{constraintElement.Key}' failed: {e.Message}", Issue.PROFILE_ELEMENTDEF_INVALID_FHIRPATH_EXPRESSION, instance); } if (!success) { var text = "Instance failed constraint " + constraintElement.ConstraintDescription(); var issue = constraintElement.Severity == ElementDefinition.ConstraintSeverity.Error ? Issue.CONTENT_ELEMENT_FAILS_ERROR_CONSTRAINT : Issue.CONTENT_ELEMENT_FAILS_WARNING_CONSTRAINT; v.Trace(outcome, text, issue, instance); } } return(outcome); ITypedElement callExternalResolver(string url) { OperationOutcome o = new OperationOutcome(); var result = v.ExternalReferenceResolutionNeeded(url, o, "dummy"); if (o.Success && result != null) { return(result); } return(null); } }
internal static OperationOutcome ValidateResourceReference(this Validator validator, ScopedNode instance, ElementDefinition.TypeRefComponent typeRef) { var outcome = new OperationOutcome(); var reference = instance.ParseResourceReference()?.Reference; if (reference == null) // No reference found -> this is always valid { return(outcome); } // Try to resolve the reference *within* the current instance (Bundle, resource with contained resources) first var referencedResource = validator.resolveReference(instance, reference, out ElementDefinition.AggregationMode? encounteredKind, outcome); // Validate the kind of aggregation. // If no aggregation is given, all kinds of aggregation are allowed, otherwise only allow // those aggregation types that are given in the Aggregation element bool hasAggregation = typeRef.Aggregation != null && typeRef.Aggregation.Count() != 0; if (hasAggregation && !typeRef.Aggregation.Any(a => a == encounteredKind)) { validator.Trace(outcome, $"Encountered a reference ({reference}) of kind '{encounteredKind}' which is not allowed", Issue.CONTENT_REFERENCE_OF_INVALID_KIND, instance); } // Bail out if we are asked to follow an *external reference* when this is disabled in the settings if (validator.Settings.ResolveExteralReferences == false && encounteredKind == ElementDefinition.AggregationMode.Referenced) { return(outcome); } // If we failed to find a referenced resource within the current instance, try to resolve it using an external method if (referencedResource == null && encounteredKind == ElementDefinition.AggregationMode.Referenced) { try { referencedResource = validator.ExternalReferenceResolutionNeeded(reference, outcome, instance.Location); } catch (Exception e) { validator.Trace(outcome, $"Resolution of external reference {reference} failed. Message: {e.Message}", Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance); } } // If the reference was resolved (either internally or externally, validate it if (referencedResource != null) { validator.Trace(outcome, $"Starting validation of referenced resource {reference} ({encounteredKind})", Issue.PROCESSING_START_NESTED_VALIDATION, instance); // References within the instance are dealt with within the same validator, // references to external entities will operate within a new instance of a validator (and hence a new tracking context). // In both cases, the outcome is included in the result. OperationOutcome childResult; if (encounteredKind != ElementDefinition.AggregationMode.Referenced) { childResult = validator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null); } else { var newValidator = validator.NewInstance(); childResult = newValidator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null); } // Prefix each path with the referring resource's path to keep the locations // interpretable foreach (var issue in childResult.Issue) { issue.Location = issue.Location.Concat(new string[] { instance.Location }); } outcome.Include(childResult); } else { validator.Trace(outcome, $"Cannot resolve reference {reference}", Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance); } return(outcome); }
internal static OperationOutcome ValidateResourceReference(this Validator validator, IElementNavigator instance, ElementDefinition.TypeRefComponent typeRef) { var outcome = new OperationOutcome(); var references = instance.GetChildrenByName("reference"); var reference = references.FirstOrDefault()?.Value as string; if (reference == null) // No reference found -> this is always valid { return(outcome); } if (references.Count() > 1) { validator.Trace(outcome, $"Encountered multiple references, just using first ({reference})", Issue.CONTENT_REFERENCE_HAS_MULTIPLE_REFERENCES, instance); } // Try to resolve the reference *within* the current instance (Bundle, resource with contained resources) first ElementDefinition.AggregationMode?encounteredKind; var referencedResource = validator.ResolveReference(instance, reference, out encounteredKind, outcome); // Validate the kind of aggregation. // If no aggregation is given, all kinds of aggregation are allowed, otherwise only allow // those aggregation types that are given in the Aggregation element bool hasAggregation = typeRef.Aggregation != null && typeRef.Aggregation.Count() != 0; if (hasAggregation && !typeRef.Aggregation.Any(a => a == encounteredKind)) { validator.Trace(outcome, $"Encountered a reference ({reference}) of kind '{encounteredKind}' which is not allowed", Issue.CONTENT_REFERENCE_OF_INVALID_KIND, instance); } // If we failed to find a referenced resource within the current instance, try to resolve it using an external method if (referencedResource == null && encounteredKind == ElementDefinition.AggregationMode.Referenced) { try { referencedResource = validator.ExternalReferenceResolutionNeeded(reference, outcome, instance); } catch (Exception e) { validator.Trace(outcome, $"Resolution of external reference {reference} failed. Message: {e.Message}", Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance); } } // If the reference was resolved (either internally or externally, validate it if (referencedResource != null) { validator.Trace(outcome, $"Starting validation of referenced resource {reference} ({encounteredKind})", Issue.PROCESSING_START_NESTED_VALIDATION, instance); // References within the instance are dealt with within the same validator, // references to external entities will operate within a new instance of a validator (and hence a new tracking context). // In both cases, the outcome is included in the result. if (encounteredKind != ElementDefinition.AggregationMode.Referenced) { outcome.Include(validator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null)); } else { var newValidator = validator.NewInstance(); outcome.Include(newValidator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null)); } } else { validator.Trace(outcome, $"Cannot resolve reference {reference}", Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance); } return(outcome); }