internal static FHIRDefinedType?DetermineType(ElementDefinition definition, IElementNavigator instance) { if (definition.IsChoice()) { if (instance.Type != null) { return(ModelInfo.FhirTypeNameToFhirType(instance.Type)); } else { return(null); } } else { return(definition.Type.First().Code.Value); } }
void merge(ElementDefinition snap, ElementDefinition diff, bool mergeElementId) { // [WMR 20160915] Important! Derived profiles should never inherit the ChangedByDiff extension // Caller should make sure that existing extensions have been removed from snap, // otherwise associated diff elems will be considered as changed (because they don't have the extension yet). // bool isExtensionConstraint = snap.Path == "Extension" || snap.IsExtension(); // paths can be changed under one circumstance: the snap is a choice[x] element, and diff limits the type choices // to one. The name can then be changed to choiceXXXX, where XXXX is the name of the type. if (snap.Path != diff.Path && snap.IsChoice() && diff.Type.Count() == 1) { // [WMR 20160906] WRONG! Must also handle snap.Path="Extension.value[x]" vs. diff.Path="Extension.extension.value[x] // if (snap.Path.Substring(0, snap.Path.Length - 3) + diff.Type.First().Code.ToString().Capitalize() != diff.Path) if (!ElementDefinitionNavigator.IsCandidateBasePath(snap.Path, diff.Path)) { throw Error.InvalidOperation($"Invalid operation in snapshot generator. Path cannot be changed from '{snap.Path}' to '{diff.Path}', since the type is sliced to '{diff.Type.First().Code}'"); } snap.PathElement = mergePrimitiveAttribute(snap.PathElement, diff.PathElement); } // [WMR 20170421] Element.Id is NOT inherited! // Merge custom Element id value from differential in same profile into snapshot // [WMR 20170424] NEW snap.ElementId = mergeId(snap, diff, mergeElementId); // representation cannot be overridden snap.NameElement = mergePrimitiveAttribute(snap.NameElement, diff.NameElement); // Codes are cumulative based on the code value // [WMR 20180611] WRONG! Invalid elementComparer // snap.Code = mergeCollection(snap.Code, diff.Code, (a, b) => a.Code == b.Code); snap.Code = mergeCollection(snap.Code, diff.Code, isEqualCoding); // For extensions, the base definition is irrelevant since they describe infrastructure, and the diff should contain the real meaning for the elements // In case the diff doesn't have these, give some generic defaults. // [WMR 20160906] Wrong! Merge extension element properties from base extension element //if (isExtensionConstraint) //{ // snap.Short = "Extension"; OnConstraint(snap.ShortElement); // snap.Definition = "An Extension"; OnConstraint(snap.DefinitionElement); // snap.Comments = null; // snap.Requirements = null; // snap.AliasElement = new List<FhirString>(); // snap.Mapping = new List<ElementDefinition.MappingComponent>(); //} snap.ShortElement = mergePrimitiveAttribute(snap.ShortElement, diff.ShortElement); snap.DefinitionElement = mergePrimitiveAttribute(snap.DefinitionElement, diff.DefinitionElement, allowAppend: true); snap.CommentsElement = mergePrimitiveAttribute(snap.CommentsElement, diff.CommentsElement, allowAppend: true); snap.RequirementsElement = mergePrimitiveAttribute(snap.RequirementsElement, diff.RequirementsElement, allowAppend: true); snap.LabelElement = mergePrimitiveAttribute(snap.LabelElement, diff.LabelElement); // Aliases are cumulative based on the string value snap.AliasElement = mergeCollection(snap.AliasElement, diff.AliasElement, (a, b) => a.Value == b.Value); // Mappings are cumulative, but keep unique on full contents snap.Mapping = mergeCollection(snap.Mapping, diff.Mapping, (a, b) => a.IsExactly(b)); snap.MinElement = mergePrimitiveAttribute(snap.MinElement, diff.MinElement); snap.MaxElement = mergePrimitiveAttribute(snap.MaxElement, diff.MaxElement); // snap.base should already be there, and is not changed by the diff // Type collection has different semantics; any change replaces the inherited type (no item merging) // i.e. derived profiles can remove inherited types if (!diff.Type.IsNullOrEmpty() && !diff.Type.IsExactly(snap.Type)) { snap.Type = new List <ElementDefinition.TypeRefComponent>(diff.Type.DeepCopy()); foreach (var element in snap.Type) { onConstraint(element); } } // ElementDefinition.nameReference cannot be overridden by a derived profile // defaultValue and meaningWhenMissing can only be set in a resource/datatype/extension definition and cannot be overridden snap.Fixed = mergeComplexAttribute(snap.Fixed, diff.Fixed); snap.Pattern = mergeComplexAttribute(snap.Pattern, diff.Pattern); snap.Example = mergeComplexAttribute(snap.Example, diff.Example); snap.MinValue = mergeComplexAttribute(snap.MinValue, diff.MinValue); snap.MaxValue = mergeComplexAttribute(snap.MaxValue, diff.MaxValue); // [WMR 20160909] merge defaultValue and meaningWhenMissing, to handle core definitions; validator can detect invalid constraints snap.DefaultValue = mergeComplexAttribute(snap.DefaultValue, diff.DefaultValue); snap.MeaningWhenMissingElement = mergePrimitiveAttribute(snap.MeaningWhenMissingElement, diff.MeaningWhenMissingElement); snap.MaxLengthElement = mergePrimitiveAttribute(snap.MaxLengthElement, diff.MaxLengthElement); // TODO: [GG] what to do about conditions? [EK] We have key, so merge Constraint and condition based on that? // Constraints are cumulative, so they are always "new" (hence a constant false for the comparer) // [WMR 20160917] Note: constraint keys must be unique. The validator will detect duplicate keys, so the derived // profile author can correct the conflicting constraint key. // [WMR 20160918] MUST merge indentical constraints, otherwise each derived profile accumulates // additional identical constraints inherited from e.g. BackboneElement. // snap.Constraint = mergeCollection(snap.Constraint, diff.Constraint, (a, b) => false); snap.Constraint = mergeCollection(snap.Constraint, diff.Constraint, (a, b) => a.IsExactly(b)); // [WMR 20160907] merge conditions snap.ConditionElement = mergeCollection(snap.ConditionElement, diff.ConditionElement, (a, b) => a.Value == b.Value); snap.MustSupportElement = mergePrimitiveAttribute(snap.MustSupportElement, diff.MustSupportElement); // [WMR 20160907] Validator should catch this // ElementDefinition.isModifier can only be overridden by a derived extension // if (isExtensionConstraint) // { snap.IsModifierElement = mergePrimitiveAttribute(snap.IsModifierElement, diff.IsModifierElement); // } snap.IsSummaryElement = mergePrimitiveAttribute(snap.IsSummaryElement, diff.IsSummaryElement); snap.Binding = mergeComplexAttribute(snap.Binding, diff.Binding); snap.Slicing = mergeComplexAttribute(snap.Slicing, diff.Slicing); // [WMR 20160817] TODO: Merge extensions // Debug.WriteLineIf(diff.Extension != null && diff.GetChangedByDiff() == null, "[ElementDefnMerger] Warning: Extension merging is not supported yet..."); // TODO: What happens to extensions present on an ElementDefinition that is overriding another? // [WMR 20160907] Merge extensions... match on url, diff completely overrides snapshot snap.Extension = mergeCollection(snap.Extension, diff.Extension, (s, d) => s.Url == d.Url); }
public void Merge(ElementDefinition snap, ElementDefinition diff) { bool isExtensionConstraint = snap.Path == "Extension" || snap.IsExtension(); // paths can be changed under one circumstance: the snap is a choice[x] element, and diff limits the type choices // to one. The name can then be changed to choiceXXXX, where XXXX is the name of the type. if (snap.Path != diff.Path && snap.IsChoice() && diff.Type.Count() == 1) { if (snap.Path.Substring(0, snap.Path.Length - 3) + diff.Type.First().Code.ToString().Capitalize() != diff.Path) { throw Error.InvalidOperation("Path cannot be changed from {0} to {1}, since the type is sliced to {2}" .FormatWith(snap.Path, diff.Path, diff.Type.First().Code)); } snap.PathElement = mergePrimitiveAttribute(snap.PathElement, diff.PathElement); } // representation cannot be overridden snap.NameElement = mergePrimitiveAttribute(snap.NameElement, diff.NameElement); // Codes are cumulative based on the code value snap.Code = mergeCollection(snap.Code, diff.Code, (a, b) => a.Code == b.Code); // For extensions, the base definition is irrelevant since they describe infrastructure, and the diff should contain the real meaning for the elements // In case the diff doesn't have these, give some generic defaults. if (isExtensionConstraint) { snap.Short = "Extension"; markChange(snap.ShortElement); snap.Definition = "An Extension"; markChange(snap.DefinitionElement); snap.Comments = null; snap.Requirements = null; snap.AliasElement = new List <FhirString>(); snap.Mapping = new List <ElementDefinition.MappingComponent>(); } snap.ShortElement = mergePrimitiveAttribute(snap.ShortElement, diff.ShortElement); snap.DefinitionElement = mergePrimitiveAttribute(snap.DefinitionElement, diff.DefinitionElement, allowAppend: true); snap.CommentsElement = mergePrimitiveAttribute(snap.CommentsElement, diff.CommentsElement, allowAppend: true); snap.RequirementsElement = mergePrimitiveAttribute(snap.RequirementsElement, diff.RequirementsElement, allowAppend: true); snap.LabelElement = mergePrimitiveAttribute(snap.LabelElement, diff.LabelElement); // Aliases are cumulative based on the string value snap.AliasElement = mergeCollection(snap.AliasElement, diff.AliasElement, (a, b) => a.Value == b.Value); // Mappings are cumulative, but keep unique on full contents snap.Mapping = mergeCollection(snap.Mapping, diff.Mapping, (a, b) => a.IsExactly(b)); snap.MinElement = mergePrimitiveAttribute(snap.MinElement, diff.MinElement); snap.MaxElement = mergePrimitiveAttribute(snap.MaxElement, diff.MaxElement); // snap.base should already be there, and is not changed by the diff // Type is just overridden if (!diff.Type.IsNullOrEmpty() && !diff.IsExactly(snap)) { snap.Type = new List <ElementDefinition.TypeRefComponent>(diff.Type.DeepCopy()); foreach (var element in snap.Type) { markChange(snap); } } // ElementDefinition.nameReference cannot be overridden by a derived profile // defaultValue and meaningWhenMissing can only be set in a resource/datatype/extension definition and cannot be overridden snap.Fixed = mergeComplexAttribute(snap.Fixed, diff.Fixed); snap.Pattern = mergeComplexAttribute(snap.Pattern, diff.Pattern); snap.Example = mergeComplexAttribute(snap.Example, diff.Example); snap.MinValue = mergeComplexAttribute(snap.MinValue, diff.MinValue); snap.MaxValue = mergeComplexAttribute(snap.MaxValue, diff.MaxValue); snap.MaxLengthElement = mergePrimitiveAttribute(snap.MaxLengthElement, diff.MaxLengthElement); // TODO: [GG] what to do about conditions? [EK] We have key, so merge Constraint and condition based on that? // Constraints are cumulative, so they are always "new" (hence a constant false for the comparer) snap.Constraint = mergeCollection(snap.Constraint, diff.Constraint, (a, b) => false); snap.MustSupportElement = mergePrimitiveAttribute(snap.MustSupportElement, diff.MustSupportElement); // ElementDefinition.isModifier can only be overridden by a derived extension if (isExtensionConstraint) { snap.IsModifierElement = mergePrimitiveAttribute(snap.IsModifierElement, diff.IsModifierElement); } snap.IsSummaryElement = mergePrimitiveAttribute(snap.IsSummaryElement, diff.IsSummaryElement); snap.Binding = mergeComplexAttribute(snap.Binding, diff.Binding); snap.Slicing = mergeComplexAttribute(snap.Slicing, diff.Slicing); // TODO: What happens to extensions present on an ElementDefinition that is overriding another? }