///------------------------------------------------------------------------------------------------- /// <summary>Process the structure primitive type.</summary> /// /// <remarks>Gino Canessa, 8/12/2019.</remarks> /// /// <param name="sd"> The SD.</param> /// <param name="filename">Filename of the file.</param> ///------------------------------------------------------------------------------------------------- static void ProcessStructurePrimitiveType(fhir.StructureDefinition sd, string filename) { //Console.WriteLine($"Primitive: {sd.Name}:{GetJsonTypeFromStructure(sd)} - {filename}"); // **** add our type **** FhirTypeManager.ProcessSpreadsheetType(sd.Name, GetPrimitiveJsonTypeFromStructure(sd), sd.Description, true, filename); }
///------------------------------------------------------------------------------------------------- /// <summary>Process the structure definition JSON file described by filename.</summary> /// /// <remarks>Gino Canessa, 8/20/2019.</remarks> /// /// <param name="sd">The SD.</param> /// /// <returns>True if it succeeds, false if it fails.</returns> ///------------------------------------------------------------------------------------------------- static bool ProcessStructureDefinition(fhir.StructureDefinition sd, string filename) { // **** skip random extensions for now **** if ((sd.Type == "Extension") && (sd.Id != "Extension")) { return(true); } // **** check for elements **** if ((sd.Snapshot == null) || (sd.Snapshot.Element == null) || (sd.Snapshot.Element.Length == 0)) { // **** nothing to do **** return(false); } // **** process each kind of definition type **** switch (sd.Kind) { case "primitive-type": ProcessStructurePrimitiveType(sd, filename); break; case "complex-type": //Console.WriteLine($"Complex type: {sd.Name} - {filename}"); ProcessStructureType(sd, filename); break; case "resource": ProcessStructureType(sd, filename); break; case "logical": Console.WriteLine($"Skipping logical type: {sd.Name} ({filename})"); break; default: Console.WriteLine($"Unknown structureDefinition.kind: {sd.Kind} for {sd.Name} ({filename})"); break; } // **** success **** return(true); }
///------------------------------------------------------------------------------------------------- /// <summary>Gets JSON type from structure.</summary> /// /// <remarks>Gino Canessa, 8/12/2019.</remarks> /// /// <param name="sd">The SD.</param> /// /// <returns>The JSON type from structure.</returns> ///------------------------------------------------------------------------------------------------- private static string GetJsonTypeFromStructure(fhir.StructureDefinition sd) { // **** check for a base **** if (!string.IsNullOrEmpty(sd.BaseDefinition)) { // **** remove most of the URL **** return(sd.BaseDefinition.Substring(sd.BaseDefinition.LastIndexOf('/') + 1)); } // **** cannot find **** return(null); }
///------------------------------------------------------------------------------------------------- /// <summary>Gets JSON type from structure.</summary> /// /// <remarks>Gino Canessa, 8/12/2019.</remarks> /// /// <param name="sd">The SD.</param> /// /// <returns>The JSON type from structure.</returns> ///------------------------------------------------------------------------------------------------- private static string GetPrimitiveJsonTypeFromStructure(fhir.StructureDefinition sd) { // **** build our value element name **** string name = $"{sd.Id}.value"; // **** loop until we find the type **** foreach (fhir.ElementDefinition element in sd.Snapshot.Element) { if (element.Id.Equals(name, StringComparison.Ordinal)) { // **** use this element *** return(GetJsonTypeFromElement(element)); } } // **** cannot find **** return(""); }
///------------------------------------------------------------------------------------------------- /// <summary>Process the structure type.</summary> /// /// <remarks>Gino Canessa, 8/20/2019.</remarks> /// /// <param name="sd"> The SD.</param> /// <param name="filename">Filename of the file.</param> ///------------------------------------------------------------------------------------------------- static void ProcessStructureType(fhir.StructureDefinition sd, string filename) { // **** figure out if this is a derived type **** string baseType = GetJsonTypeFromStructure(sd); if (string.IsNullOrEmpty(baseType)) { // **** use the base type **** baseType = sd.Type; } // **** reformat circular references **** if (baseType.Equals(sd.Id, StringComparison.Ordinal)) { baseType = ""; } // **** traverse the elements **** for (int elementIndex = 0; elementIndex < sd.Snapshot.Element.Length; elementIndex++) { fhir.ElementDefinition element = sd.Snapshot.Element[elementIndex]; // **** check for initial element (need to change type) **** if (elementIndex == 0) { // **** use the base type **** FhirTypeManager.ProcessSpreadsheetDataElement( sd.Name, baseType, sd.Description, $"{element.Min}..{element.Max}", false, filename ); // **** check for defining a base type **** if (!element.Id.Equals(sd.Name, StringComparison.Ordinal)) { // **** make sure this node exists too **** FhirTypeManager.ProcessSpreadsheetDataElement( element.Id, element.Base.Path, element.Definition, $"{element.Min}..{element.Max}", false, filename ); } // **** no more processing for this entry **** continue; } // **** check for inherited property **** if ((element.Base != null) && (!string.IsNullOrEmpty(element.Base.Path)) && (!element.Base.Path.Equals(element.Id, StringComparison.Ordinal))) { // **** skip this **** continue; } // **** check for type information **** if ((element.Type != null) && (element.Type.Length > 0) && (element.Type[0].Code != null)) { // **** grab the valueSet if present **** string valueSet = ""; if ((element.Binding != null) && (!string.IsNullOrEmpty(element.Binding.ValueSet))) { valueSet = element.Binding.ValueSet; } string cardinality = element.Type.Length > 1 ? "0..1" : $"{element.Min}..{element.Max}"; // **** traverse the types for this element **** foreach (ElementDefinitionType defType in element.Type) { string typeCode = defType.Code; // **** check for the FHIR Type extension **** if ((defType.Extension != null) && (defType.Extension.Length > 0)) { foreach (Extension ext in defType.Extension) { if (ext.Url.Equals( "http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type", StringComparison.Ordinal)) { typeCode = ext.ValueUrl ?? ext.ValueUri; } } } // **** remove array info from name (if necessary) **** string elementName = element.Path.Replace( "[x]", string.Concat( typeCode.Substring(0, 1).ToUpper(), typeCode.Substring(1) ) ); // **** check for a code type **** if (typeCode == "code") { string[] codeValues = element.Short.Split('|'); // **** process this field **** FhirTypeManager.ProcessSpreadsheetDataElement( elementName, typeCode, (element.Comment == null) ? element.Definition : element.Comment, $"{element.Min}..{element.Max}", false, filename, codeValues ); // **** done with this field **** continue; } // **** process this field **** FhirTypeManager.ProcessSpreadsheetDataElement( elementName, typeCode, element.Definition, cardinality, false, filename, valueSet: valueSet ); } } // **** check for extension type information **** else if ((element.Type != null) && (element.Type.Length > 0) && (element.Type[0].Extension != null)) { // **** find the json type **** string propertyType = ""; foreach (Extension ext in element.Type[0].Extension) { if (ext.Url.EndsWith("fhir-type")) { propertyType = ext.ValueUrl ?? ext.ValueUri; break; } } // **** process this field **** FhirTypeManager.ProcessSpreadsheetDataElement( element.Path, propertyType, element.Definition, $"{element.Min}..{element.Max}", false, filename ); } // **** check for extension type information **** else if ((element.Type != null) && (element.Type.Length > 0) && (element.Type[0]._Code != null)) { // **** find the json type **** string propertyType = ""; foreach (Extension ext in element.Type[0]._Code.Extension) { if (ext.Url.EndsWith("json-type")) { propertyType = ext.ValueString; break; } } // **** process this field **** FhirTypeManager.ProcessSpreadsheetDataElement( element.Path, propertyType, element.Definition, $"{element.Min}..{element.Max}", false, filename ); } // **** use base path **** else { // **** grab the assumed type **** string propertyType = ""; // **** check for override **** if (!string.IsNullOrEmpty(element.ContentReference)) { propertyType = FhirPathToCamelCase(element.ContentReference); } // **** assume base path if nothing else filled out **** if (string.IsNullOrEmpty(propertyType)) { propertyType = FhirPathToCamelCase(element.Base.Path); } // **** process this field **** FhirTypeManager.ProcessSpreadsheetDataElement( element.Path, propertyType, element.Definition, $"{element.Min}..{element.Max}", false, filename ); } } }
static bool ProcessPublishedJson(Options options) { string dir = Path.Combine(options.FhirDirectory, "publish"); // **** check for this directory existing **** if (!Directory.Exists(dir)) { Console.WriteLine("Publish directory not found!"); return(false); } // **** get all canonical files in the publish directory **** string[] files = Directory.GetFiles(dir, "*.canonical.json", SearchOption.AllDirectories); // **** traverse the files **** foreach (string filename in files) { // **** read the contents **** string contents = File.ReadAllText(filename); // **** act depending on contents **** if (contents.Contains("\"resourceType\":\"StructureDefinition\"")) { // **** check for ignoring these **** if (options.UseOnlyXmlSpreadsheets) { continue; } // **** parse into an object we can work with **** fhir.StructureDefinition sd = JsonConvert.DeserializeObject <fhir.StructureDefinition>(contents); // **** process this structure definition **** ProcessStructureDefinition(sd, filename); // **** done with this file **** continue; } if (contents.Contains("\"resourceType\":\"CodeSystem\"")) { if (options.ExcludeCodeSystems) { continue; } // **** parse into an object we can work with **** fhir.CodeSystem cs = JsonConvert.DeserializeObject <fhir.CodeSystem>(contents); // **** process this code system **** FhirTypeManager.LoadCodeSystem(cs); // **** done with this file **** continue; } if (contents.Contains("\"resourceType\":\"ValueSet\"")) { if (options.ExcludeValueSets) { continue; } // **** parse into an object we can work with **** fhir.ValueSet vs = JsonConvert.DeserializeObject <fhir.ValueSet>(contents); // **** process this value set **** FhirTypeManager.LoadValueSet(vs, filename); // **** done with this file **** continue; } } // **** success ***** return(true); }