internal static OperationOutcome ValidateType(this Validator validator, ElementDefinition definition, ScopedNavigator instance) { var outcome = new OperationOutcome(); validator.Trace(outcome, "Validating against constraints specified by the element's defined type", Issue.PROCESSING_PROGRESS, instance); if(definition.Type.Any(tr => tr.Code == null)) validator.Trace(outcome, "ElementDefinition contains a type with an empty type code", Issue.PROFILE_ELEMENTDEF_CONTAINS_NULL_TYPE, instance); // Check if this is a choice: there are multiple distinct Codes to choose from var typeRefs = definition.Type.Where(tr => tr.Code != null); var choices = typeRefs.Select(tr => tr.Code.Value).Distinct(); if (choices.Count() > 1) { if (instance.Type != null) { // This is a choice type, find out what type is present in the instance data // (e.g. deceased[Boolean], or _resourceType in json). This is exposed by IElementNavigator.TypeName. var instanceType = ModelInfo.FhirTypeNameToFhirType(instance.Type); if (instanceType != null) { // In fact, the next statements are just an optimalization, without them, we would do an ANY validation // against *all* choices, what we do here is pre-filtering for sensible choices, and report if there isn't // any. var applicableChoices = typeRefs.Where(tr => ModelInfo.IsInstanceTypeFor(tr.Code.Value, instanceType.Value)); // Instance typename must be one of the applicable types in the choice if (applicableChoices.Any()) { outcome.Include(validator.ValidateTypeReferences(applicableChoices, instance)); } else { var choiceList = String.Join(",", choices.Select(t => "'" + t.GetLiteral() + "'")); validator.Trace(outcome, $"Type specified in the instance ('{instance.Type}') is not one of the allowed choices ({choiceList})", Issue.CONTENT_ELEMENT_HAS_INCORRECT_TYPE, instance); } } else validator.Trace(outcome, $"Instance indicates the element is of type '{instance.Type}', which is not a known FHIR core type.", Issue.CONTENT_ELEMENT_CHOICE_INVALID_INSTANCE_TYPE, instance); } else validator.Trace(outcome, "ElementDefinition is a choice or contains a polymorphic type constraint, but the instance does not indicate its actual type", Issue.CONTENT_ELEMENT_CANNOT_DETERMINE_TYPE, instance); } else if (choices.Count() == 1) { // Only one type present in list of typerefs, all of the typerefs are candidates outcome.Include(validator.ValidateTypeReferences(typeRefs, instance)); } return outcome; }