
001package org.hl7.fhir.r5.renderers.spreadsheets; 002 003import java.io.FileOutputStream; 004import java.io.IOException; 005import java.io.OutputStream; 006import java.util.List; 007 008import lombok.extern.slf4j.Slf4j; 009import org.apache.poi.ss.usermodel.Row; 010import org.apache.poi.ss.usermodel.Sheet; 011import org.hl7.fhir.exceptions.DefinitionException; 012import org.hl7.fhir.r5.context.IWorkerContext; 013import org.hl7.fhir.r5.context.SimpleWorkerContext; 014import org.hl7.fhir.r5.model.CanonicalType; 015import org.hl7.fhir.r5.model.CodeSystem; 016import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent; 017import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; 018import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent; 019import org.hl7.fhir.r5.model.ElementDefinition; 020import org.hl7.fhir.r5.model.Enumeration; 021import org.hl7.fhir.r5.model.Enumerations.FilterOperator; 022import org.hl7.fhir.r5.model.ValueSet; 023import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; 024import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 025import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent; 026import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; 027import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent; 028import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent; 029import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 030import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 031import org.hl7.fhir.utilities.i18n.I18nConstants; 032 033@MarkedToMoveToAdjunctPackage 034@Slf4j 035public class CodeSystemSpreadsheetGenerator extends CanonicalSpreadsheetGenerator { 036 037 public CodeSystemSpreadsheetGenerator(IWorkerContext context) { 038 super(context); 039 } 040 041 public boolean canGenerate(CodeSystem cs) { 042 return true; 043 } 044 045 public CodeSystemSpreadsheetGenerator renderCodeSystem(CodeSystem cs) throws IOException { 046 if (cs == null) { 047 log.warn("no code system!"); 048 } 049 addCodeSystemMetadata(renderCanonicalResource(cs, false), cs); 050 051 if (cs.hasProperty()) { 052 addProperties(cs.getProperty()); 053 } 054 if (cs.hasFilter()) { 055 addFilters(cs.getFilter()); 056 } 057 if (cs.hasConcept()) { 058 addConcepts(cs.getConcept()); 059 } 060 return this; 061 } 062 063 private void addCodeSystemMetadata(Sheet sheet, CodeSystem cs) { 064 addMetadataRow(sheet, "Case Sensitive", cs.getCaseSensitiveElement().asStringValue()); 065 addMetadataRow(sheet, "Value Set (all codes)", cs.getValueSet()); 066 addMetadataRow(sheet, "Hierarchy", cs.getHierarchyMeaningElement().asStringValue()); 067 addMetadataRow(sheet, "Compositional", cs.getCompositionalElement().asStringValue()); 068 addMetadataRow(sheet, "Version Needed?", cs.getVersionNeededElement().asStringValue()); 069 addMetadataRow(sheet, "Content", cs.getContentElement().asStringValue()); 070 addMetadataRow(sheet, "Supplements", cs.getSupplements()); 071 addMetadataRow(sheet, "Count", cs.getCountElement().asStringValue()); 072 } 073 074 private void addFilters(List<CodeSystemFilterComponent> filters) { 075 Sheet sheet = makeSheet("Filters"); 076 addHeaders(sheet, "Code", "Description", "Operators", "Value"); 077 for (CodeSystemFilterComponent f : filters) { 078 CommaSeparatedStringBuilder cs = new CommaSeparatedStringBuilder(); 079 for (Enumeration<FilterOperator> op : f.getOperator()) { 080 cs.append(op.asStringValue()); 081 } 082 addRow(sheet, f.getCode(), f.getDescription(), cs.toString(), f.getValue()); 083 } 084 } 085 086 private void addProperties(List<PropertyComponent> properties) { 087 Sheet sheet = makeSheet("Properties"); 088 addHeaders(sheet, "Code", "Uri", "Description", "Type"); 089 for (PropertyComponent p : properties) { 090 addRow(sheet, p.getCode(), p.getUri(), p.getDescription(), p.getTypeElement().asStringValue()); 091 } 092 } 093 094 private void addConcepts(List<ConceptDefinitionComponent> concepts) { 095 Sheet sheet = makeSheet("Concepts"); 096 addHeaders(sheet, "Level", "Code", "Display", "Definition"); //todo: properties and designations 097 addConcepts(sheet, 1, concepts); 098 } 099 100 private void addConcepts(Sheet sheet, int i, List<ConceptDefinitionComponent> concepts) { 101 for (ConceptDefinitionComponent c : concepts) { 102 addRow(sheet, Integer.toString(i), c.getCode(), c.getDisplay(), c.getDefinition()); 103 if (c.hasConcept()) { 104 addConcepts(sheet, i+1, c.getConcept()); 105 } 106 } 107 } 108 109 private void genExpansionParams(List<ValueSetExpansionParameterComponent> params) { 110 Sheet sheet = makeSheet("Expansion Parameters"); 111 addHeaders(sheet, "Parameter", "Value"); 112 for (ValueSetExpansionParameterComponent p : params) { 113 addRow(sheet, p.getName(), dr.displayDataType(p.getValue())); 114 } 115 } 116 117 private void genExpansion(List<ValueSetExpansionContainsComponent> list) { 118 Sheet sheet = makeSheet("Expansion"); 119 addHeaders(sheet, "Level", "System", "version", "Code", "Display", "Abstract", "Inactive"); 120 genExpansionEntry(1, list, sheet); 121 } 122 123 public void genExpansionEntry(int level, List<ValueSetExpansionContainsComponent> list, Sheet sheet) { 124 for (ValueSetExpansionContainsComponent p : list) { 125 addRow(sheet, Integer.toString(level), p.getSystem(), p.getVersion(), p.getCode(), p.getDisplay(), bool(p.getAbstract()), bool(p.getInactive())); 126 if (p.hasContains()) { 127 genExpansionEntry(level + 1, p.getContains(), sheet); 128 } 129 } 130 } 131 132 private String bool(boolean value) { 133 return value ? "" : "false"; 134 } 135 136// private void genInclude(ValueSet vs, ConceptSetComponent inc, String mode) { 137// if (inc.hasSystem()) { 138// genIncludeSystem(vs, inc, mode); 139// } else { 140// genIncludeValueSets(vs, inc, mode); 141// } 142// String subname = inc.hasSystem() ? : "ValueSets"; 143// 144// 145// Row headerRow = sheet.createRow(0); 146// for (int i = 0; i < titles.length; i++) { 147// addCell(headerRow, i, titles[i], styles.get("header")); 148// } 149// int i = titles.length - 1; 150// for (StructureDefinitionMappingComponent map : sd.getMapping()) { 151// i++; 152// addCell(headerRow, i, "Mapping: " + map.getName(), styles.get("header")); 153// } 154// 155// for (ElementDefinition child : sd.getSnapshot().getElement()) { 156// processElement(sheet, sd, child); 157// } 158// configureSheet(sheet, sd); 159// } 160 161// private void genIncludeValueSets(ValueSet vs, ConceptSetComponent inc, String mode) { 162// Sheet sheet = makeSheet(mode+" ValueSets"); 163// addValueSets(sheet, inc.getValueSet()); 164// configureSheet(sheet); 165// } 166// 167// private void genIncludeSystem(ValueSet vs, ConceptSetComponent inc, String mode) { 168// Sheet sheet = makeSheet(mode+" from "+dr.displaySystem(inc.getSystem())); 169// if (inc.hasValueSet()) { 170// addValueSets(sheet, inc.getValueSet()); 171// } 172// if (inc.hasFilter()) { 173// addFilters(sheet, inc.getFilter()); 174// } 175// if (inc.hasConcept()) { 176// addConcepts(sheet, inc.getConcept()); 177// } 178// if (!inc.hasConcept() && !inc.hasFilter()) { 179// addAllCodes(sheet); 180// } 181// addRow(sheet, "", ""); 182// addRow(sheet, "System URI", inc.getSystem()); 183// 184// configureSheet(sheet); 185// } 186 187 private void addAllCodes(Sheet sheet) { 188 addHeaders(sheet, "Codes"); 189 addRow(sheet, "All codes"); 190 } 191 192 private void addValueSets(Sheet sheet, List<CanonicalType> valueSets) { 193 addHeaders(sheet, "ValueSet URL"); 194 for (CanonicalType u : valueSets) { 195 addRow(sheet, u.getValue()); 196 } 197 } 198 199 private void configureSheet(Sheet sheet) { 200 sheet.setColumnWidth(0, columnPixels(30)); 201 sheet.setColumnWidth(1, columnPixels(40)); 202 sheet.setColumnWidth(1, columnPixels(50)); 203 } 204 205 private void addConcepts(Sheet sheet, List<ConceptReferenceComponent> concepts) { 206 addHeaders(sheet, "Concept", "Description"); // todo: designations 207 for (ConceptReferenceComponent cd : concepts) { 208 addRow(sheet, cd.getCode(), cd.getDisplay()); 209 } 210 } 211 212 private void addFilters(Sheet sheet, List<ConceptSetFilterComponent> filters) { 213 addHeaders(sheet, "Property", "Operation", "Value"); 214 for (ConceptSetFilterComponent f : filters) { 215 addRow(sheet, f.getProperty(), f.getOpElement().asStringValue(), f.getValue()); 216 } 217 } 218 219}