internal OperationOutcome ValidateConstraints(ElementDefinition definition, IElementNavigator instance) { // Make sure FHIR extensions are installed in FP compiler PocoNavigatorExtensions.PrepareFhirSymbolTableFunctions(); var outcome = new OperationOutcome(); if (Settings.SkipConstraintValidation) { return(outcome); } var context = ScopeTracker.ResourceContext(instance); // <constraint> // <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-expression"> // <valueString value="reference.startsWith('#').not() or (reference.substring(1).trace('url') in %resource.contained.id.trace('ids'))"/> // </extension> // <key value="ref-1"/> // <severity value="error"/> // <human value="SHALL have a local reference if the resource is provided inline"/> // <xpath value="not(starts-with(f:reference/@value, '#')) or exists(ancestor::*[self::f:entry or self::f:parameter]/f:resource/f:*/f:contained/f:*[f:id/@value=substring-after(current()/f:reference/@value, '#')]|/*/f:contained/f:*[f:id/@value=substring-after(current()/f:reference/@value, '#')])"/> //</constraint> // foreach (var constraintElement in definition.Constraint) { var fpExpression = constraintElement.GetFhirPathConstraint(); if (fpExpression != null) { try { bool success = instance.Predicate(fpExpression, context); 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; Trace(outcome, text, issue, instance); } } catch (Exception e) { Trace(outcome, $"Evaluation of FhirPath for constraint '{constraintElement.Key}' failed: {e.Message}", Issue.PROFILE_ELEMENTDEF_INVALID_FHIRPATH_EXPRESSION, instance); } } else { Trace(outcome, $"Encountered an invariant ({constraintElement.Key}) that has no FhirPath expression, skipping validation of this constraint", Issue.UNSUPPORTED_CONSTRAINT_WITHOUT_FHIRPATH, instance); } } return(outcome); }
/// <summary> /// Perform the Invariant based validation for this rule /// </summary> /// <param name="invariantRule"></param> /// <param name="model"></param> /// <param name="result">The OperationOutcome that will have the validation results appended</param> /// <returns></returns> protected static bool ValidateInvariantRule(ElementDefinition.ConstraintComponent invariantRule, IElementNavigator model, OperationOutcome result) { string expression = invariantRule.GetStringExtension("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression"); try { // No FhirPath extension if (string.IsNullOrEmpty(expression)) { result.Issue.Add(new OperationOutcome.IssueComponent() { Code = OperationOutcome.IssueType.Invariant, Severity = OperationOutcome.IssueSeverity.Warning, Details = new CodeableConcept(null, invariantRule.Key, "Unable to validate without a FhirPath expression"), Diagnostics = expression }); return(true); } // Ensure the FHIR extensions are registered Hl7.Fhir.FhirPath.PocoNavigatorExtensions.PrepareFhirSybolTableFunctions(); if (model.Predicate(expression, model)) { return(true); } result.Issue.Add(new OperationOutcome.IssueComponent() { Code = OperationOutcome.IssueType.Invariant, Severity = OperationOutcome.IssueSeverity.Error, Details = new CodeableConcept(null, invariantRule.Key, invariantRule.Human), Diagnostics = expression }); return(false); } catch (Exception ex) { result.Issue.Add(new OperationOutcome.IssueComponent() { Code = OperationOutcome.IssueType.Invariant, Severity = OperationOutcome.IssueSeverity.Fatal, Details = new CodeableConcept(null, invariantRule.Key, "FATAL: Unable to process the invariant rule: " + invariantRule.Key + " " + expression), Diagnostics = String.Format("FhirPath: {0}\r\nError: {1}", expression, ex.Message) }); return(false); } }
public static bool Predicate(this IElementNavigator input, string expression, IElementNavigator resource) { return(input.Predicate(expression, new EvaluationContext(resource))); }