/// <summary> /// Gets the @id value of the element/constraint. /// </summary> /// <param name="constraint"></param> /// <returns></returns> /// <remarks>Creates the value based on the context of the constraint and each parent, and based on whether the parents are a branch</remarks> public static string GetElementId(this TemplateConstraint constraint) { string elementId = string.Empty; TemplateConstraint current = constraint; bool checkBranch = true; while (current != null) { string separator = current.IsChoice ? ":" : "."; if (!string.IsNullOrEmpty(elementId)) { elementId = separator + elementId; } if (checkBranch && current.IsBranch) { elementId = current.GetElementPath(constraint.Template.PrimaryContextType) + ":" + current.GetSliceName() + elementId; checkBranch = false; } else { elementId = current.Context + elementId; } current = current.ParentConstraint; } if (checkBranch) { return(constraint.Template.PrimaryContextType + "." + elementId); } return(elementId); }
public void GetFHIRElementPathTest() { TemplateConstraint tc1 = new TemplateConstraint(); tc1.Context = "extension"; TemplateConstraint tc2 = new TemplateConstraint(); tc2.Context = "value[x]"; tc2.IsChoice = true; tc2.ParentConstraint = tc1; TemplateConstraint tc3 = new TemplateConstraint(); tc3.Context = "valueCodeableConcept"; tc3.ParentConstraint = tc2; string path1 = tc1.GetElementPath("Observation"); string path2 = tc2.GetElementPath("Observation"); string path3 = tc3.GetElementPath("Observation"); Assert.AreEqual("Observation.extension", path1); Assert.AreEqual("Observation.extension.value[x]", path2); Assert.AreEqual("Observation.extension.valueCodeableConcept", path3); }
public void CreateElementDefinition( StructureDefinition strucDef, TemplateConstraint constraint, SimpleSchema.SchemaObject schemaObject) { if (constraint.IsPrimitive) // Skip primitives (for now, at least) { return; } string sliceName = constraint.GetSliceName(); string elementPath = constraint.GetElementPath(strucDef.Type != null ? strucDef.Type.ToString() : null); var igSettings = GetIGSettings(constraint); var constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, this.igTypePlugin, constraint); string definition = constraintFormatter.GetPlainText(false, false, false); if (definition == null) { definition = string.Empty; } ElementDefinition newElementDef = new ElementDefinition() { Short = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : constraint.Context, Label = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : null, Comment = !string.IsNullOrEmpty(constraint.Notes) ? constraint.Notes : null, Path = elementPath, SliceName = sliceName, Definition = definition, ElementId = constraint.GetElementId() }; if (constraint.IsChoice) { newElementDef.Slicing = new ElementDefinition.SlicingComponent(); newElementDef.Slicing.Discriminator.Add(new ElementDefinition.DiscriminatorComponent() { Type = ElementDefinition.DiscriminatorType.Type, Path = "$this" }); newElementDef.Slicing.Rules = ElementDefinition.SlicingRules.Open; } else if (constraint.Parent != null && constraint.Parent.IsChoice) { newElementDef.SliceName = constraint.Context; } // Cardinality if (!string.IsNullOrEmpty(constraint.Cardinality)) { newElementDef.Min = constraint.CardinalityType.Left; newElementDef.Max = constraint.CardinalityType.Right == Cardinality.MANY ? "*" : constraint.CardinalityType.Right.ToString(); } // Binding string valueConformance = string.IsNullOrEmpty(constraint.ValueConformance) ? constraint.Conformance : constraint.ValueConformance; bool hasBinding = constraint.References.Any(y => y.ReferenceType == ConstraintReferenceTypes.Template); if (constraint.ValueSet != null && valueConformance.IndexOf("NOT") < 0) { hasBinding = true; newElementDef.Binding = new ElementDefinition.ElementDefinitionBindingComponent() { ValueSet = new ResourceReference() { Reference = constraint.ValueSet.GetIdentifier(ValueSetIdentifierTypes.HTTP), Display = constraint.ValueSet.Name } }; if (valueConformance == "SHALL") { newElementDef.Binding.Strength = BindingStrength.Required; } else if (valueConformance == "SHOULD") { newElementDef.Binding.Strength = BindingStrength.Preferred; } else if (valueConformance == "MAY") { newElementDef.Binding.Strength = BindingStrength.Example; } } // Single-Value Binding if (schemaObject != null && (!string.IsNullOrEmpty(constraint.Value) || !string.IsNullOrEmpty(constraint.DisplayName))) { Element elementBinding = null; hasBinding = true; switch (schemaObject.DataType) { case "CodeableConcept": var codableConceptBinding = new CodeableConcept(); var coding = new Coding(); codableConceptBinding.Coding.Add(coding); if (!string.IsNullOrEmpty(constraint.Value)) { coding.Code = constraint.Value; } if (constraint.CodeSystem != null) { coding.System = constraint.CodeSystem.Oid; } if (!string.IsNullOrEmpty(constraint.DisplayName)) { coding.Display = constraint.DisplayName; } elementBinding = codableConceptBinding; break; case "Coding": var codingBinding = new Coding(); if (!string.IsNullOrEmpty(constraint.Value)) { codingBinding.Code = constraint.Value; } if (constraint.CodeSystem != null) { codingBinding.System = constraint.CodeSystem.Oid; } if (!string.IsNullOrEmpty(constraint.DisplayName)) { codingBinding.Display = constraint.DisplayName; } elementBinding = codingBinding; break; case "code": var codeBinding = new Code(); codeBinding.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName; elementBinding = codeBinding; break; default: var stringBinding = new FhirString(); stringBinding.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName; elementBinding = stringBinding; break; } if (constraint.IsFixed) { newElementDef.Fixed = elementBinding; } else { newElementDef.Pattern = elementBinding; } } // Add the type of the element when bound to a value set if (hasBinding && schemaObject != null && !string.IsNullOrEmpty(schemaObject.DataType)) { StructureDefinition profile = GetBaseProfile(constraint.Template); newElementDef.Type = GetProfileDataTypes(profile, constraint); var containedTemplates = (from tcr in constraint.References join t in this.tdb.Templates on tcr.ReferenceIdentifier equals t.Oid where tcr.ReferenceType == ConstraintReferenceTypes.Template select new { Identifier = t.Oid, t.PrimaryContextType }); // If there is a contained template/profile, make sure it supports a "Reference" type, and then output the profile identifier in the type if (containedTemplates.Count() > 0 && newElementDef.Type.Exists(y => y.Code == "Reference" || y.Code == "Extension")) { if (!string.IsNullOrEmpty(newElementDef.SliceName)) { var foundMatchingElement = strucDef.Differential.Element.SingleOrDefault(y => y.Path == newElementDef.Path && y.SliceName == newElementDef.SliceName); if (foundMatchingElement != null) { foundMatchingElement.Definition += " " + definition; newElementDef = foundMatchingElement; } } var containedTypes = new List <ElementDefinition.TypeRefComponent>(); foreach (var containedTemplate in containedTemplates) { bool isExtension = containedTemplate.PrimaryContextType == "Extension" && newElementDef.Type.Exists(y => y.Code == "Extension"); containedTypes.Add(new ElementDefinition.TypeRefComponent() { Code = isExtension ? "Extension" : "Reference", Profile = isExtension ? containedTemplate.Identifier : null, TargetProfile = !isExtension ? containedTemplate.Identifier : null }); } newElementDef.Type = containedTypes; } } // Add the element to the list if it's new if (!strucDef.Differential.Element.Contains(newElementDef)) { strucDef.Differential.Element.Add(newElementDef); } // Children foreach (var childConstraint in constraint.ChildConstraints.OrderBy(y => y.Order)) { var childSchemaObject = schemaObject != null?schemaObject.Children.SingleOrDefault(y => y.Name == childConstraint.Context) : null; CreateElementDefinition(strucDef, childConstraint, childSchemaObject); } }
public void CreateElementDefinition( StructureDefinition strucDef, TemplateConstraint constraint, SimpleSchema.SchemaObject schemaObject, string sliceName = null) { if (constraint.IsPrimitive) // Skip primitives (for now, at least) { return; } string newSliceName = null; if (constraint.IsBranch) { newSliceName = string.Format("{0}_slice_pos{1}", constraint.Context, constraint.Order); } var igSettings = GetIGSettings(constraint); var constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, this.igTypePlugin, constraint); ElementDefinition newElementDef = new ElementDefinition() { Short = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : constraint.Context, Label = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : null, Comments = !string.IsNullOrEmpty(constraint.Notes) ? constraint.Notes : null, Path = constraint.GetElementPath(strucDef.ConstrainedType), Name = constraint.IsBranch ? newSliceName : sliceName, Definition = constraintFormatter.GetPlainText(false, false, false) }; // Cardinality if (!string.IsNullOrEmpty(constraint.Cardinality)) { newElementDef.Min = constraint.CardinalityType.Left; newElementDef.Max = constraint.CardinalityType.Right == Cardinality.MANY ? "*" : constraint.CardinalityType.Right.ToString(); } // Binding string valueConformance = string.IsNullOrEmpty(constraint.ValueConformance) ? constraint.Conformance : constraint.ValueConformance; bool hasBinding = constraint.References.Any(y => y.ReferenceType == ConstraintReferenceTypes.Template); if (constraint.ValueSet != null && valueConformance.IndexOf("NOT") < 0) { hasBinding = true; newElementDef.Binding = new ElementDefinition.ElementDefinitionBindingComponent() { ValueSet = new ResourceReference() { Reference = string.Format("ValueSet/{0}", constraint.ValueSet.Id), Display = constraint.ValueSet.Name } }; if (valueConformance == "SHALL") { newElementDef.Binding.Strength = BindingStrength.Required; } else if (valueConformance == "SHOULD") { newElementDef.Binding.Strength = BindingStrength.Preferred; } else if (valueConformance == "MAY") { newElementDef.Binding.Strength = BindingStrength.Example; } } // Single-Value Binding if (schemaObject != null && (!string.IsNullOrEmpty(constraint.Value) || !string.IsNullOrEmpty(constraint.DisplayName))) { hasBinding = true; switch (schemaObject.DataType) { case "CodeableConcept": var fixedCodeableConcept = new CodeableConcept(); var coding = new Coding(); fixedCodeableConcept.Coding.Add(coding); if (!string.IsNullOrEmpty(constraint.Value)) { coding.Code = constraint.Value; } if (constraint.CodeSystem != null) { coding.System = constraint.CodeSystem.Oid; } if (!string.IsNullOrEmpty(constraint.DisplayName)) { coding.Display = constraint.DisplayName; } newElementDef.Fixed = fixedCodeableConcept; break; case "Coding": var fixedCoding = new Coding(); if (!string.IsNullOrEmpty(constraint.Value)) { fixedCoding.Code = constraint.Value; } if (constraint.CodeSystem != null) { fixedCoding.System = constraint.CodeSystem.Oid; } if (!string.IsNullOrEmpty(constraint.DisplayName)) { fixedCoding.Display = constraint.DisplayName; } newElementDef.Fixed = fixedCoding; break; case "code": var fixedCode = new Code(); fixedCode.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName; newElementDef.Fixed = fixedCode; break; default: var fixedString = new FhirString(); fixedString.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName; newElementDef.Fixed = fixedString; break; } } // Add the type of the element when bound to a value set if (hasBinding && schemaObject != null && !string.IsNullOrEmpty(schemaObject.DataType)) { StructureDefinition profile = GetBaseProfile(constraint.Template); newElementDef.Type = GetProfileDataTypes(profile, constraint); var containedTemplates = (from tcr in constraint.References join t in this.tdb.Templates on tcr.ReferenceIdentifier equals t.Oid where tcr.ReferenceType == ConstraintReferenceTypes.Template select new { Identifier = t.Oid, t.PrimaryContextType }); // If there is a contained template/profile, make sure it supports a "Reference" type, and then output the profile identifier in the type if (containedTemplates.Count() > 0 && newElementDef.Type.Exists(y => y.Code == "Reference" || y.Code == "Extension")) { var containedTypes = new List <ElementDefinition.TypeRefComponent>(); foreach (var containedTemplate in containedTemplates) { bool isExtension = containedTemplate.PrimaryContextType == "Extension" && newElementDef.Type.Exists(y => y.Code == "Extension"); containedTypes.Add(new ElementDefinition.TypeRefComponent() { Code = isExtension ? "Extension" : "Reference", Profile = new List <string>(new string[] { containedTemplate.Identifier }) }); } newElementDef.Type = containedTypes; } } // Add the element to the list strucDef.Differential.Element.Add(newElementDef); // Children foreach (var childConstraint in constraint.ChildConstraints.OrderBy(y => y.Order)) { var childSchemaObject = schemaObject != null?schemaObject.Children.SingleOrDefault(y => y.Name == childConstraint.Context) : null; CreateElementDefinition(strucDef, childConstraint, childSchemaObject, newSliceName); } }