11package org .opencds .cqf .tooling .terminology ;
22
3+ import ca .uhn .fhir .context .FhirContext ;
4+ import ca .uhn .fhir .parser .IParser ;
35import java .io .File ;
46import java .io .FileInputStream ;
57import java .io .FileOutputStream ;
68import java .io .IOException ;
79import java .util .Map ;
810
9- import org .apache .poi .ss .usermodel .Cell ;
10- import org .apache .poi .ss .usermodel .DataFormatter ;
11- import org .apache .poi .ss .usermodel .Row ;
12- import org .apache .poi .ss .usermodel .Workbook ;
11+ import org .apache .poi .ss .usermodel .*;
1312import org .apache .poi .xssf .usermodel .XSSFWorkbook ;
14-
15- import ca .uhn .fhir .context .FhirContext ;
16- import ca .uhn .fhir .parser .IParser ;
1713import org .opencds .cqf .tooling .utilities .IOUtils ;
1814
1915public class SpreadsheetHelper {
@@ -29,19 +25,17 @@ public static Workbook getWorkbook(String pathToSpreadsheet) {
2925
3026 private static String cleanseString (String rawValue ) {
3127 StringBuilder newString = new StringBuilder (rawValue .length ());
32- for (int offset = 0 ; offset < rawValue .length ();)
33- {
28+ for (int offset = 0 ; offset < rawValue .length (); ) {
3429 int codePoint = rawValue .codePointAt (offset );
3530 offset += Character .charCount (codePoint );
3631
3732 // Replace invisible control characters and unused code points
38- switch (Character .getType (codePoint ))
39- {
40- case Character .CONTROL : // \p{Cc}
41- case Character .FORMAT : // \p{Cf}
33+ switch (Character .getType (codePoint )) {
34+ case Character .CONTROL : // \p{Cc}
35+ case Character .FORMAT : // \p{Cf}
4236 case Character .PRIVATE_USE : // \p{Co}
43- case Character .SURROGATE : // \p{Cs}
44- case Character .UNASSIGNED : // \p{Cn}
37+ case Character .SURROGATE : // \p{Cs}
38+ case Character .UNASSIGNED : // \p{Cn}
4539 newString .append ('?' );
4640 break ;
4741 default :
@@ -54,20 +48,18 @@ private static String cleanseString(String rawValue) {
5448
5549 private static String cleanseStringNoReplacement (String rawValue ) {
5650 StringBuilder newString = new StringBuilder (rawValue .length ());
57- for (int offset = 0 ; offset < rawValue .length ();)
58- {
51+ for (int offset = 0 ; offset < rawValue .length (); ) {
5952 int codePoint = rawValue .codePointAt (offset );
6053 offset += Character .charCount (codePoint );
6154
6255 // Replace invisible control characters and unused code points
63- switch (Character .getType (codePoint ))
64- {
65- case Character .CONTROL : // \p{Cc}
66- case Character .FORMAT : // \p{Cf}
56+ switch (Character .getType (codePoint )) {
57+ case Character .CONTROL : // \p{Cc}
58+ case Character .FORMAT : // \p{Cf}
6759 case Character .PRIVATE_USE : // \p{Co}
68- case Character .SURROGATE : // \p{Cs}
69- case Character .UNASSIGNED : // \p{Cn}
70- //just skip it
60+ case Character .SURROGATE : // \p{Cs}
61+ case Character .UNASSIGNED : // \p{Cn}
62+ // just skip it
7163 break ;
7264 default :
7365 newString .append (Character .toChars (codePoint ));
@@ -83,12 +75,11 @@ public static String protectedString(String rawValue, boolean replace) {
8375 return result ;
8476 }
8577 result = result .trim ();
86- if (replace ) {
78+ if (replace ) {
8779 result = result .replaceAll ("\\ p{Cntrl}" , "?" );
8880 result = result .replaceAll ("\\ p{C}" , "?" );
8981 result = SpreadsheetHelper .cleanseString (result );
90- }
91- else {
82+ } else {
9283 result = result .replaceAll ("\\ p{Cntrl}" , "" );
9384 result = result .replaceAll ("\\ p{C}" , "" );
9485 result = SpreadsheetHelper .cleanseStringNoReplacement (result );
@@ -97,6 +88,7 @@ public static String protectedString(String rawValue, boolean replace) {
9788 }
9889
9990 private static DataFormatter dataFormatter ;
91+
10092 public static DataFormatter getDataFormatter () {
10193 if (dataFormatter == null ) {
10294 dataFormatter = new DataFormatter ();
@@ -137,7 +129,25 @@ public static String getCellAsString(Row row, int cellIndex) {
137129 return null ;
138130 }
139131
140- //name.matches('[A-Z]([A-Za-z0-9_]){0,254}')
132+ public static String getCellAsStringEmptyForNull (Cell cell , FormulaEvaluator evaluator ) {
133+ if (cell == null ) return "" ;
134+
135+ DataFormatter formatter = SpreadsheetHelper .getDataFormatter ();
136+ String raw = (evaluator == null ) ? formatter .formatCellValue (cell ) : formatter .formatCellValue (cell , evaluator );
137+
138+ // Normalize NBSP/newlines and trim to empty
139+ if (raw == null ) return "" ;
140+ return raw .replace ("\n " , " " ).replace ('\u00A0' , ' ' ).trim ();
141+ }
142+
143+ public static String getCellAsStringEmptyForNull (Row row , int cellIndex , FormulaEvaluator evaluator ) {
144+ if (row == null || cellIndex < 0 ) return "" ;
145+ // create a blank cell if missing so we never return null
146+ Cell cell = row .getCell (cellIndex , Row .MissingCellPolicy .CREATE_NULL_AS_BLANK );
147+ return getCellAsStringEmptyForNull (cell , evaluator );
148+ }
149+
150+ // name.matches('[A-Z]([A-Za-z0-9_]){0,254}')
141151 public static String getFHIRName (String value ) {
142152 String name = value .replaceAll ("[^A-Za-z0-9_]" , "" );
143153 while (name .length () > 0 && !Character .isAlphabetic (name .charAt (0 ))) {
@@ -151,18 +161,23 @@ public static String getFHIRName(String value) {
151161 public static void resolveValueSet (org .hl7 .fhir .dstu3 .model .ValueSet vs , Map <Integer , ValueSet > codesBySystem ) {
152162 vs .setCompose (new org .hl7 .fhir .dstu3 .model .ValueSet .ValueSetComposeComponent ());
153163 for (Map .Entry <Integer , org .opencds .cqf .tooling .terminology .ValueSet > entry : codesBySystem .entrySet ()) {
154- org .hl7 .fhir .dstu3 .model .ValueSet .ConceptSetComponent component = new org .hl7 .fhir .dstu3 .model .ValueSet .ConceptSetComponent ();
155- component .setSystem (entry .getValue ().getSystem ()).setVersion (entry .getValue ().getVersion ()).setConcept (entry .getValue ().getCodes ());
164+ org .hl7 .fhir .dstu3 .model .ValueSet .ConceptSetComponent component =
165+ new org .hl7 .fhir .dstu3 .model .ValueSet .ConceptSetComponent ();
166+ component
167+ .setSystem (entry .getValue ().getSystem ())
168+ .setVersion (entry .getValue ().getVersion ())
169+ .setConcept (entry .getValue ().getCodes ());
156170 vs .setCompose (vs .getCompose ().addInclude (component ));
157171 }
158172 }
159173
160174 public static void writeValueSetToFile (org .hl7 .fhir .dstu3 .model .ValueSet vs , String encoding , String outputPath ) {
161- String fileName = vs .getTitle () != null ? vs .getTitle ().replaceAll ("\\ s" , "" ).concat ("." + encoding ) : "valueset" .concat ("." + encoding );
162- IParser parser =
163- encoding == null
164- ? FhirContext .forDstu3Cached ().newJsonParser ()
165- : encoding .toLowerCase ().startsWith ("j" )
175+ String fileName = vs .getTitle () != null
176+ ? vs .getTitle ().replaceAll ("\\ s" , "" ).concat ("." + encoding )
177+ : "valueset" .concat ("." + encoding );
178+ IParser parser = encoding == null
179+ ? FhirContext .forDstu3Cached ().newJsonParser ()
180+ : encoding .toLowerCase ().startsWith ("j" )
166181 ? FhirContext .forDstu3Cached ().newJsonParser ()
167182 : FhirContext .forDstu3Cached ().newXmlParser ();
168183 try (FileOutputStream writer = new FileOutputStream (IOUtils .concatFilePath (outputPath , fileName ))) {
0 commit comments