ElementTreeSlice SliceSection(ElementTreeNode sliceElementDef, String sliceName, String title, Coding code, out ElementDefinition entry) { ElementTreeSlice slice = sliceElementDef.CreateSlice(sliceName); CreateElement(slice, "title") .Single() .Fixed(new FhirString(title)) ; CreateElement(slice, "code") .Single() .Pattern(code.ToCodeableConcept().ToPattern()) .DefaultValueExtension(code.ToCodeableConcept()) ; CreateElement(slice, "focus") .Zero() ; entry = CreateElement(slice, "entry") ; CreateElement(slice, "section") .Zero() ; return(slice); }
public void SimpleMod() { StructureDefinition original = this.CreateBaseObservation(); StructureDefinition modified = this.CreateBaseObservation(); SnapshotCreator.Create(original); SnapshotCreator.Create(modified); ElementTreeLoader loader = new ElementTreeLoader(info); ElementTreeNode originalNode = loader.Create(original.Snapshot.Element); ElementTreeNode modifiedNode = loader.Create(modified.Snapshot.Element); Assert.True(modifiedNode.TryGetElementNode("Observation.value[x]", out ElementTreeNode n)); n.ElementDefinition.Max = "0"; ElementTreeDiffer differ = new ElementTreeDiffer(info); differ.Process(originalNode, modifiedNode); List <ElementDefinition> elementDefinitions = new List <ElementDefinition>(); modifiedNode.CopyTo(elementDefinitions); Assert.True(elementDefinitions.Count == 2); Assert.True(elementDefinitions[1].Path == "Observation.value[x]"); Assert.True(elementDefinitions[1].Max == "0"); }
public bool Process(ElementTreeNode original, ElementTreeNode modified) { successFlag = true; this.ProcessNode(original, modified); return(successFlag); }
void FixDifferential(ProcessItem processedItem) { const String fcn = "FixDifferentials"; StructureDefinition sDef = (StructureDefinition)processedItem.Resource; this.ConversionInfo(this.GetType().Name, fcn, $"Computing differential for {processedItem.Resource.GetName()}"); ElementTreeNode differentialNode = processedItem.SnapNode.Clone(); { ElementTreeDiffer differ = new ElementTreeDiffer(this); if (differ.Process(processedItem.SnapNodeOriginal, differentialNode) == false) { return; } } { ElementTreeSetBase setBase = new ElementTreeSetBase(this); if (setBase.Process(processedItem.SnapNodeOriginal, differentialNode) == false) { return; } } { processedItem.DiffNode = differentialNode; List <ElementDefinition> elementDefinitions = new List <ElementDefinition>(); differentialNode.CopyTo(elementDefinitions); sDef.Differential.Element = elementDefinitions; } }
void SliceOid(String sliceName, String shortText, Markdown definition, out ElementTreeSlice extensionSlice, out ElementTreeNode valueXNode ) { Self.Slice(e, extensionNode, sliceName, shortText, definition, out extensionSlice, out valueXNode ); valueXNode.ElementDefinition .Type("oid") .Single() ; e.AddComponentLink(sliceName.ToMachineName(), new SDefEditor.Cardinality(extensionSlice.ElementDefinition), null, Global.ElementAnchor(extensionSlice.ElementDefinition), "Oid"); }
/// <summary> /// Bubble sort of nodes in list. /// Nodes are sorted according to the position values stored in /// order, which si usually created from the snapshot of the base resource. /// If tow items with the same name are found in the list, then the relative order of the items /// will be kept, so that the item that was first will still be first. This si done to keep Slice elements /// in the same order as they were defined. /// </summary> void SortNodes(List <ElementTreeNode> nodes, Dictionary <String, Int32> order) { if (nodes.Count == 0) { return; } int length = nodes.Count; ElementTreeNode temp = nodes[0]; for (int i = 0; i < length; i++) { if (order.TryGetValue(nodes[i].Name, out Int32 iVal) == false) { throw new Exception($"Sort error. Can not find index of {nodes[i].Name}"); } for (int j = i + 1; j < length; j++) { if (order.TryGetValue(nodes[j].Name, out Int32 jVal) == false) { throw new Exception($"Sort error. Can not find index of {nodes[j].Name}"); } if (iVal > jVal) { temp = nodes[i]; nodes[i] = nodes[j]; nodes[j] = temp; } } } }
public BuildMemberElement(DefineBase defineBase, ClassCodeBlocks codeBlocks, ElementTreeNode valueNode) : base(defineBase, codeBlocks) { this.valueNode = valueNode; }
/// <summary> /// Create structure definition editor /// </summary> public SDefEditor(IConversionInfo info, String name, String url, String baseDefinition, String mapName, String fragmentDir, String pageDir) { this.info = info; this.fragmentDir = fragmentDir; this.pageDir = pageDir; this.baseSDef = FhirStructureDefinitions.Self.GetResource(baseDefinition); if (this.baseSDef == null) { throw new Exception($"'Base definition resource {baseDefinition}' not found"); } this.basePath = baseDefinition.LastUriPart(); { ElementTreeLoader l = new ElementTreeLoader(); this.snapNode = l.Create(this.baseSDef.Snapshot.Element); this.snapNodeOriginal = this.snapNode.Clone(); } this.sDef = new StructureDefinition { Name = name, Url = url, BaseDefinition = baseDefinition, Differential = new StructureDefinition.DifferentialComponent() }; this.SDef.AddExtension(Global.ResourceMapNameUrl, new FhirString(mapName)); }
public ElementTreeSlice ApplyExtension(ElementTreeNode extDef, String name, String extensionUrl) { String sliceName = name.UncapFirstLetter(); this.ConfigureSliceByUrlDiscriminator(extDef, true); ElementTreeSlice slice = extDef.CreateSlice(sliceName); slice.ElementDefinition.Min = 0; slice.ElementDefinition.Max = "*"; slice.ElementDefinition .SetShort($"{name} extension.") .SetDefinition(new Markdown() .Paragraph($"This extension slice contains the {name} extension.")) .SetComment(ResourcesMaker.componentDefinition) ; slice.ElementDefinition.IsModifier = false; slice.ElementDefinition.Type.Add(new ElementDefinition.TypeRefComponent { Code = "Extension", Profile = new String[] { extensionUrl } }); return(slice); }
public bool Write(out String fragmentName) { fragmentName = null; this.sDef.Snapshot = null; // Create differential by comparing current snapshot with original. ElementTreeNode differentialNode = this.snapNode.Clone(); { ElementTreeDiffer differ = new ElementTreeDiffer(this.info); if (differ.Process(this.snapNodeOriginal, differentialNode) == false) { return(false); } } { ElementTreeSetBase setBase = new ElementTreeSetBase(this.info); if (setBase.Process(this.snapNodeOriginal, differentialNode) == false) { return(false); } } // Patch Path and Id's with correct basePath. differentialNode.ReplaceBasePath(this.basePath); { List <ElementDefinition> elementDefinitions = new List <ElementDefinition>(); differentialNode.CopyTo(elementDefinitions); this.sDef.Differential.Element = elementDefinitions; } fragmentName = Path.Combine(this.fragmentDir, $"StructureDefinition-{this.sDef.Name}.json"); // Make sure that all Observation resources that are not fragments, have Observation.code // fixed properly. if ( (this.sDef.IsFragment() == false) && (this.sDef.BaseDefinition == Global.ObservationUrl) ) { if (this.snapNode.TryGetElementNode("Observation.code", out ElementTreeNode codeNode) == false) { throw new Exception("Observation.code not found"); } if (codeNode.ElementDefinition.Pattern == null) { this.info.ConversionError(nameof(SDefEditor), "Write", $"Observation {this.SDef.Name} lacks fixed Observation.code."); } } SnapshotCreator.Create(this.sDef); this.sDef.SaveJson(fragmentName); return(true); }
public BuildMemberComponents(DefineBase defineBase, ClassCodeBlocks codeBlocks, ElementTreeNode componentNode) : base(defineBase, codeBlocks) { this.memberNode = componentNode; this.fhirName = this.memberNode.ElementDefinition.Path.LastPathPart(); }
void SortElements(ElementTreeNode orderTemplateNode, ElementTreeNode itemsNode) { foreach (ElementTreeSlice itemsSlice in itemsNode.Slices) { SortSlice(orderTemplateNode.DefaultSlice, itemsSlice); } }
public BuildMemberReferences(DefineBase defineBase, ClassCodeBlocks codeBlocks, ElementTreeNode memberNode) : base(defineBase, codeBlocks) { this.memberNode = memberNode; this.fhirName = memberNode.ElementDefinition.Path.LastPathPart(); }
void ProcessNode(ElementTreeNode originalNode, ElementTreeNode modifiedNode) { foreach (ElementTreeSlice modifiedSlice in modifiedNode.Slices) { ProcessSlice(originalNode.DefaultSlice, modifiedSlice); } }
/// <summary> /// Perform local processing of container class. /// </summary> protected override void BuildContainerClassLocal(ClassCodeBlocks codeBlocks) { base.BuildContainerClassLocal(codeBlocks); ElementTreeNode urlNode = this.extensionSlice.Nodes["url"]; String extensionUrl = ((FhirUri)urlNode.ElementDefinition.Fixed).Value; codeBlocks.ClassProperties .AppendCode($"public const String ExtensionUrl = \"{extensionUrl}\";") ; }
public ElementTreeSlice AppendSlice(String elementName, String sliceName, Int32 min = 0, String max = "*") { ElementTreeNode elementDef = this.Get(elementName); ElementTreeSlice retVal = elementDef.CreateSlice(sliceName); retVal.ElementDefinition.Min = min; retVal.ElementDefinition.Max = max; return(retVal); }
public ElementDefinition SliceSelfByPattern(String path, String sliceName, Element pattern) { ElementTreeNode elementDef = ApplySliceSelf(path); sliceName = sliceName.UncapFirstLetter(); ElementTreeSlice codingSlice = elementDef.CreateSlice(sliceName); codingSlice.ElementDefinition.Pattern = pattern; return(codingSlice.ElementDefinition); }
/// <summary> /// Build a class to implement an extension. /// This determines if a simple extension is to be defined, /// or a complex extension. /// </summary> public void Build() { //$ TODO: Implement validation const String fcn = "Build"; ElementDefinition extensionDef = this.extensionSlice.ElementDefinition; if ( (extensionDef.Type.Count == 1) && (extensionDef.Type[0].Code == "Extension") ) { if (extensionDef.Type[0].Profile.Count() > 0) { if (extensionDef.Type[0].Profile.Count() != 1) { throw new Exception($"Invalid extension ProfileProfile definition {this.extensionName}"); } if (this.extensionSlice.Nodes.Count > 0) { throw new Exception($"Invalid eternal extension {this.extensionName}. Nodes.Count == {this.extensionSlice.Nodes.Count}. Expected 0."); } BuildExtensionReference(extensionDef); return; } } ElementTreeNode valueXNode = this.extensionSlice.Nodes.GetItem("value[x]"); ElementTreeNode subExtensionNode = this.extensionSlice.Nodes.GetItem("extension"); Int32 valueXCardMax = CSMisc.ToMax(valueXNode.ElementDefinition.Max); if ((valueXCardMax != 0) && (subExtensionNode.Slices.Count > 1)) { // Cant build both simple and complex extension. throw new Exception($"Both Simple and Complex extension found. Not implemented"); } else if ((valueXCardMax == 0) && (subExtensionNode.Slices.Count == 0)) { // Neither simple and complex extension? throw new Exception($"Neither Simple and Complex extension found. Not implemented"); } else if (valueXCardMax != 0) { // Build Simple Extension this.BuildOneSimpleExtension(this.extensionName); } else { // Build Complex Extension this.BuildOneComplexExtension(this.extensionName); } }
public void SliceSize(ElementTreeSlice slice, ValueSet units) { // Fix component code ElementTreeNode valueXNode = this.SliceValueXByType(slice, new string[] { "Quantity", "Range" }); { Hl7.Fhir.Model.Quantity q = new Hl7.Fhir.Model.Quantity { System = units.Url }; ElementDefinition valueX = new ElementDefinition { Path = $"{slice.ElementDefinition.Path}.value[x]", ElementId = $"{slice.ElementDefinition.ElementId}.value[x]:valueQuantity", SliceName = $"valueQuantity", Min = 0, Max = "1" } .Pattern(q) .Type("Quantity") ; valueXNode.CreateSlice($"valueQuantity", valueX); } { Hl7.Fhir.Model.Range r = new Hl7.Fhir.Model.Range { Low = new SimpleQuantity { System = units.Url, }, High = new SimpleQuantity { System = units.Url, } }; ElementDefinition valueX = new ElementDefinition { Path = $"{slice.ElementDefinition.Path}.value[x]", ElementId = $"{slice.ElementDefinition.ElementId}.value[x]:valueRange", SliceName = $"valueRange", Min = 0, Max = "1" } .Pattern(r) .Type("Range") ; valueXNode.CreateSlice($"valueRange", valueX); } }
bool MergeElementTreeSlice(ElementTreeSlice baseSlice, ElementTreeSlice mergeSlice) { const String fcn = "MergeElementTreeSlice"; bool retVal = true; foreach (ElementTreeNode mergeNode in mergeSlice.Nodes) { ElementTreeNode baseNode = null; if (!baseSlice.Nodes.TryGetItem(mergeNode.Name, out baseNode)) { // see if element definition is something like {CodeableConcept}.coding. if ( (baseItem.SnapNodeOriginal.TryGetElementNode(baseSlice.ElementDefinition.Path, out ElementTreeNode originalNode) == false) || (this.IsElementPart(originalNode.ElementDefinition, mergeNode.Name) == false) ) { this.preFhir.ConversionError(this.GetType().Name, fcn, $"Node '{mergeNode.Path}' does not exist in base. Can not add element to non-fragment"); return(false); } if (this.preFhir.DebugFlag) { this.preFhir.ConversionInfo(this.GetType().Name, fcn, $"Node '{mergeNode.Path}' does not exist in base. Copying whole node"); } // Node doesnt exist in base, so copy it whole. baseNode = mergeNode.Clone(); baseNode.ReplaceBasePath(this.baseItem.BasePath); baseSlice.Nodes.Add(baseNode); } else { if (this.preFhir.DebugFlag) { this.preFhir.ConversionInfo(this.GetType().Name, fcn, $"Node '{mergeNode.Path}' found in base. Merging node"); } if (!MergeElementTreeNode(baseNode, mergeNode)) { retVal = false; } } } return(retVal); }
bool MergeElementTreeNode(ElementTreeNode baseNode, ElementTreeNode mergeNode) { const String fcn = "MergeElementTreeNode"; bool retVal = true; if (this.BreakOnElementId != null) { if (baseNode.ElementDefinition.ElementId == this.BreakOnElementId) { Debugger.Break(); } } foreach (ElementTreeSlice mergeSlice in mergeNode.Slices) { if (!baseNode.Slices.TryGetItem(mergeSlice.Name, out ElementTreeSlice baseSlice)) { // slice doesn't exist in base, so copy it whole. if (this.preFhir.DebugFlag) { this.preFhir.ConversionInfo(this.GetType().Name, fcn, $"Slice '{mergeSlice.Name}' not found in base. Cloning node"); } baseSlice = mergeSlice.Clone(baseNode); baseSlice.ReplaceBasePath(this.baseItem.BasePath); baseNode.Slices.Add(baseSlice); } else { if (this.preFhir.DebugFlag) { this.preFhir.ConversionInfo(this.GetType().Name, fcn, $"Slice '{mergeSlice.Name}' found in base. Merging slice"); } MergeExtensions(baseNode.ElementDefinition.Extension, mergeNode.ElementDefinition.Extension); if (!Constrain(baseNode.ElementDefinition, mergeNode.ElementDefinition)) { retVal = false; } if (!MergeElementTreeSlice(baseSlice, mergeSlice)) { retVal = false; } } } return(retVal); }
/// <summary> /// Add an element. /// </summary> /// <param name=""></param> /// <returns></returns> public void AddElement(String path, ElementDefinition elementDefinition) { ElementTreeNode currentItem = this; ElementTreeSlice slice = currentItem.DefaultSlice; String[] pathItems = path.Split('.'); for (Int32 i = 0; i < pathItems.Length; i++) { String pathItem = pathItems[i]; String[] pathItemParts = pathItem.Split(':'); String pathPart; String sliceName; switch (pathItemParts.Length) { case 1: pathPart = pathItemParts[0]; sliceName = DefaultSliceName; break; case 2: pathPart = pathItemParts[0]; sliceName = pathItemParts[1]; break; default: throw new Exception($"Error parsing path item {pathItem}"); } if (i < pathItems.Length - 1) { if (slice.Nodes.TryGetItem(pathPart, out currentItem) == false) { throw new Exception($"Node {pathPart} in {path} not found"); } if (currentItem.Slices.TryGetItem(sliceName, out slice) == false) { throw new Exception($"Slice {pathPart} in {path} not found"); } } else { if (slice.Nodes.TryGetItem(pathPart, out currentItem) == true) { throw new Exception($"Node {pathPart} of {path} already exists"); } slice.CreateNode(path, path.LastPathPart(), elementDefinition); } } }
void Slice(SDefEditor e, ElementTreeNode extensionNode, String sliceName, String shortText, Markdown definition, out ElementTreeSlice extensionSlice, out ElementTreeNode valueXNode) { extensionSlice = extensionNode.CreateSlice(sliceName); extensionSlice.ElementDefinition .ElementId($"{extensionNode.ElementDefinition.Path}:{sliceName}") .SliceName(sliceName) .Short(shortText) .Definition(definition) .SetCardinality(0, "1") ; extensionSlice.ElementDefinition.Type = null; { ElementDefinition sealExtension = new ElementDefinition { ElementId = $"{extensionNode.ElementDefinition.Path}:{sliceName}.extension", Path = $"{extensionNode.ElementDefinition.Path}.extension" }; sealExtension.Zero(); extensionSlice.CreateNode(sealExtension); } { ElementDefinition elementUrl = new ElementDefinition() .Path($"{extensionNode.ElementDefinition.Path}.url") .ElementId($"{extensionNode.ElementDefinition.Path}:{sliceName}.url") .Value(new FhirUri(sliceName)) .Type("uri") .Definition(new Markdown() .Paragraph($"Url for {sliceName} complex extension item.") ) ; extensionSlice.CreateNode(elementUrl); } { ElementDefinition valueBase = e.Get("value[x]").ElementDefinition; ElementDefinition elementValue = new ElementDefinition() .Path($"{extensionNode.ElementDefinition.Path}.value[x]") .ElementId($"{extensionNode.ElementDefinition.Path}:{sliceName}.value[x]") ; valueXNode = extensionSlice.CreateNode(elementValue); } }
/// <summary> /// Clone /// </summary> public ElementTreeNode Clone() { ElementTreeNode retVal = new ElementTreeNode { Name = this.Name, Path = this.Path }; foreach (ElementTreeSlice slice in this) { retVal.Slices.Add(slice.Clone(this)); } return(retVal); }
public bool Add(ElementTreeNode head, IEnumerable <ElementDefinition> items) { const String fcn = "Add"; Int32 itemIndex = 0; Load("", head.DefaultSlice, items.ToArray(), ref itemIndex); if (itemIndex != items.Count()) { this.Error(this.GetType().Name, fcn, $"Loader error. Unconsumed elements leftover...."); return(false); } return(true); }
void SetBaseDef(String baseDefinition) { if ( (this.baseDef != null) && (this.baseDef.Url == baseDefinition) ) { return; } this.baseDef = FhirStructureDefinitions.Self.GetResource(baseDefinition); ElementTreeLoader l = new ElementTreeLoader(); this.snapNode = l.Create(this.baseDef.Snapshot.Element); }
void SliceAndBindUrl(SDefEditor e, ElementTreeNode extensionNode, String sliceName, String bindName, String shortText, Markdown definition, out ElementTreeSlice extensionSlice, out ElementTreeNode valueXNode) { this.Slice(e, extensionNode, sliceName, shortText, definition, out extensionSlice, out valueXNode); valueXNode.ElementDefinition .Type("CodeableConcept") .Binding(bindName, BindingStrength.Required) .Single() ; }
public override void Build() { Int32 max = CSMisc.ToMax(this.extensionSlice.ElementDefinition.Max); Int32 min = this.extensionSlice.ElementDefinition.Min.Value; ElementTreeNode valueNode = this.extensionSlice.Nodes["value[x]"]; this.itemElementSetName.Clear(); foreach (var type in valueNode.ElementDefinition.Type) { this.itemElementSetName.Add(type.Code); } this.itemElementGetName = (this.itemElementSetName.Count == 1) ? valueNode.ElementDefinition.Type[0].Code : "Element"; base.BuildOne(this.extensionSlice.ElementDefinition.ElementId, min, max); }
public ElementTreeSlice SliceByUrlTarget(ElementTreeNode sliceElementDef, String profileUrl, Int32 min, String max) { String sliceName = profileUrl.LastUriPart().UncapFirstLetter(); ElementTreeSlice slice = sliceElementDef.CreateSlice(sliceName); slice.ElementDefinition.SetCardinality(min, max); slice.ElementDefinition.Type.Clear(); slice.ElementDefinition.Type.Add(new ElementDefinition.TypeRefComponent { Code = "Reference", TargetProfile = new String[] { profileUrl } }); return(slice); }
public void StartComponentSliceing() { ElementTreeNode componentNode = this.Get("component"); ElementDefinition.SlicingComponent slicingComponent = new ElementDefinition.SlicingComponent { Rules = ElementDefinition.SlicingRules.Open }; slicingComponent.Discriminator.Add(new ElementDefinition.DiscriminatorComponent { Type = ElementDefinition.DiscriminatorType.Pattern, Path = "code" }); componentNode.ApplySlicing(slicingComponent, false); }