001package org.hl7.fhir.dstu3.utils.formats; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu3 006 * %% 007 * Copyright (C) 2014 - 2019 Health Level 7 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023 024import java.io.ByteArrayOutputStream; 025import java.io.IOException; 026import java.io.OutputStream; 027import java.io.UnsupportedEncodingException; 028import java.util.ArrayList; 029import java.util.Enumeration; 030import java.util.List; 031 032import org.hl7.fhir.dstu3.formats.IParser.OutputStyle; 033import org.hl7.fhir.dstu3.formats.JsonParser; 034import org.hl7.fhir.dstu3.formats.XmlParser; 035import org.hl7.fhir.dstu3.model.Coding; 036import org.hl7.fhir.dstu3.model.ElementDefinition; 037import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionConstraintComponent; 038import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionMappingComponent; 039import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent; 040import org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent; 041import org.hl7.fhir.dstu3.model.IdType; 042import org.hl7.fhir.dstu3.model.Reference; 043import org.hl7.fhir.dstu3.model.StringType; 044import org.hl7.fhir.dstu3.model.StructureDefinition; 045import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionMappingComponent; 046import org.hl7.fhir.dstu3.model.Type; 047import org.hl7.fhir.dstu3.model.UriType; 048import org.hl7.fhir.utilities.TextStreamWriter; 049 050 051public class CSVWriter extends TextStreamWriter { 052 053 private StructureDefinition def; 054 private List<StructureDefinitionMappingComponent> mapKeys = new ArrayList<StructureDefinitionMappingComponent>(); 055 private List<CSVLine> lines = new ArrayList<CSVLine>(); 056 private XmlParser xml = new XmlParser(); 057 private JsonParser json = new JsonParser(); 058 private boolean asXml; 059 060 private class CSVLine { 061 private String line = ""; 062 063 public void addString(String s) { 064 line = line + (line.equals("") ? "":",") + "\"" + csvEscape(s) + "\""; 065 } 066 067 public void addString(StringType s) { 068 addString(s==null? "" : s.getValue()); 069 } 070 071 public void addValue(String s) { 072 line = line + (line.equals("") ? "":",") + s; 073 } 074 075 public void addValue(int s) { 076 line = line + (line.equals("") ? "":",") + s; 077 } 078 079 public void addBoolean(boolean b) { 080 addValue(b ? "Y" : ""); 081 } 082 083 protected String csvEscape(String s) { 084 if (s==null) 085 return ""; 086 else if (s.contains("\"")) 087 return s.substring(0,s.indexOf("\"")) + "\"\"" + csvEscape(s.substring(s.indexOf("\"")+1)); 088 else 089 return s; 090 } 091 092 public String toString() { 093 return line; 094 } 095 } 096 097 public CSVWriter(OutputStream out, StructureDefinition def, boolean asXml) throws UnsupportedEncodingException { 098 super(out); 099 this.asXml = asXml; 100 this.def = def; 101 CSVLine header = new CSVLine(); 102 lines.add(header); 103 header.addString("Path"); //A 104 header.addString("Slice Name"); //B 105 header.addString("Alias(s)"); //C 106 header.addString("Label"); //D 107 header.addString("Min"); //E 108 header.addString("Max"); //F 109 header.addString("Must Support?"); //G 110 header.addString("Is Modifier?"); //H 111 header.addString("Is Summary?"); //I 112 header.addString("Type(s)"); //J 113 header.addString("Short"); //K 114 header.addString("Definition"); //L 115 header.addString("Comments"); //M 116 header.addString("Requirements"); //N 117 header.addString("Default Value"); //O 118 header.addString("Meaning When Missing"); //P 119 header.addString("Fixed Value"); //Q 120 header.addString("Pattern"); //R 121 header.addString("Example"); //S 122 header.addString("Minimum Value"); //T 123 header.addString("Maximum Value"); //U 124 header.addString("Maximum Length"); //V 125 header.addString("Binding Strength"); //W 126 header.addString("Binding Description"); //X 127 header.addString("Binding Value Set"); //Y 128 header.addString("Code"); //Z 129 header.addString("Slicing Discriminator");//AA 130 header.addString("Slicing Description"); //AB 131 header.addString("Slicing Ordered"); //AC 132 header.addString("Slicing Rules"); //AD 133 header.addString("Base Path"); //AE 134 header.addString("Base Min"); //AF 135 header.addString("Base Max"); //AG 136 header.addString("Condition(s)"); //AH 137 header.addString("Constraint(s)"); //AI 138 for (StructureDefinitionMappingComponent map : def.getMapping()) { 139 header.addString("Mapping: " + map.getName()); 140 } 141 } 142 143/* private void findMapKeys(StructureDefinition def, List<StructureDefinitionMappingComponent> maps, IWorkerContext context) { 144 maps.addAll(def.getMapping()); 145 if (def.getBaseDefinition()!=null) { 146 StructureDefinition base = context.fetchResource(StructureDefinition.class, def.getBaseDefinition()); 147 findMapKeys(base, maps, context); 148 } 149 }*/ 150 151 public void processElement(ElementDefinition ed) throws Exception { 152 CSVLine line = new CSVLine(); 153 lines.add(line); 154 line.addString(ed.getPath()); 155 line.addString(ed.getSliceName()); 156 line.addString(itemList(ed.getAlias())); 157 line.addString(ed.getLabel()); 158 line.addValue(ed.getMin()); 159 line.addValue(ed.getMax()); 160 line.addString(ed.getMustSupport() ? "Y" : ""); 161 line.addString(ed.getIsModifier() ? "Y" : ""); 162 line.addString(ed.getIsSummary() ? "Y" : ""); 163 line.addString(itemList(ed.getType())); 164 line.addString(ed.getShort()); 165 line.addString(ed.getDefinition()); 166 line.addString(ed.getComment()); 167 line.addString(ed.getRequirements()); 168 line.addString(ed.getDefaultValue()!=null ? renderType(ed.getDefaultValue()) : ""); 169 line.addString(ed.getMeaningWhenMissing()); 170 line.addString(ed.hasFixed() ? renderType(ed.getFixed()) : ""); 171 line.addString(ed.hasPattern() ? renderType(ed.getPattern()) : ""); 172 line.addString(ed.hasExample() ? renderType(ed.getExample().get(0).getValue()) : ""); // todo...? 173 line.addString(ed.hasMinValue() ? renderType(ed.getMinValue()) : ""); 174 line.addString(ed.hasMaxValue() ? renderType(ed.getMaxValue()) : ""); 175 line.addValue((ed.hasMaxLength() ? Integer.toString(ed.getMaxLength()) : "")); 176 if (ed.hasBinding()) { 177 line.addString(ed.getBinding().getStrength()!=null ? ed.getBinding().getStrength().toCode() : ""); 178 line.addString(ed.getBinding().getDescription()); 179 if (ed.getBinding().getValueSet()==null) 180 line.addString(""); 181 else if (ed.getBinding().getValueSet() instanceof Reference) 182 line.addString(ed.getBinding().getValueSetReference().getReference()); 183 else 184 line.addString(ed.getBinding().getValueSetUriType().getValue()); 185 } else { 186 line.addValue(""); 187 line.addValue(""); 188 line.addValue(""); 189 } 190 line.addString(itemList(ed.getCode())); 191 if (ed.hasSlicing()) { 192 line.addString(itemList(ed.getSlicing().getDiscriminator())); 193 line.addString(ed.getSlicing().getDescription()); 194 line.addBoolean(ed.getSlicing().getOrdered()); 195 line.addString(ed.getSlicing().getRules()!=null ? ed.getSlicing().getRules().toCode() : ""); 196 } else { 197 line.addValue(""); 198 line.addValue(""); 199 line.addValue(""); 200 } 201 if (ed.getBase()!=null) { 202 line.addString(ed.getBase().getPath()); 203 line.addValue(ed.getBase().getMin()); 204 line.addValue(ed.getBase().getMax()); 205 } else { 206 line.addValue(""); 207 line.addValue(""); 208 line.addValue(""); 209 } 210 line.addString(itemList(ed.getCondition())); 211 line.addString(itemList(ed.getConstraint())); 212 for (StructureDefinitionMappingComponent mapKey : def.getMapping()) { 213 for (ElementDefinitionMappingComponent map : ed.getMapping()) { 214 if (map.getIdentity().equals(mapKey.getIdentity())) 215 line.addString(map.getMap()); 216 } 217 } 218 } 219 220 221 private String itemList(List l) { 222 StringBuilder s = new StringBuilder(); 223 for (int i =0; i< l.size(); i++) { 224 Object o = l.get(i); 225 String val = ""; 226 if (o instanceof StringType) { 227 val = ((StringType)o).getValue(); 228 } else if (o instanceof UriType) { 229 val = ((UriType)o).getValue(); 230 } else if (o instanceof IdType) { 231 val = ((IdType)o).getValue(); 232 } else if (o instanceof Enumeration<?>) { 233 val = o.toString(); 234 } else if (o instanceof TypeRefComponent) { 235 TypeRefComponent t = (TypeRefComponent)o; 236 val = t.getCode() + (t.getProfile() == null ? "" : " {" + t.getProfile() + "}") +(t.getTargetProfile() == null ? "" : " {" + t.getTargetProfile() + "}") + (t.getAggregation() == null || t.getAggregation().isEmpty() ? "" : " (" + itemList(t.getAggregation()) + ")"); 237 } else if (o instanceof Coding) { 238 Coding t = (Coding)o; 239 val = (t.getSystem()==null ? "" : t.getSystem()) + (t.getCode()==null ? "" : "#" + t.getCode()) + (t.getDisplay()==null ? "" : " (" + t.getDisplay() + ")"); 240 } else if (o instanceof ElementDefinitionConstraintComponent) { 241 ElementDefinitionConstraintComponent c = (ElementDefinitionConstraintComponent)o; 242 val = c.getKey() + ":" + c.getHuman() + " {" + c.getExpression() + "}"; 243 } else if (o instanceof ElementDefinitionSlicingDiscriminatorComponent) { 244 ElementDefinitionSlicingDiscriminatorComponent c = (ElementDefinitionSlicingDiscriminatorComponent)o; 245 val = c.getType().toCode() + ":" + c.getPath() + "}"; 246 247 } else { 248 val = o.toString(); 249 val = val.substring(val.indexOf("[")+1); 250 val = val.substring(0, val.indexOf("]")); 251 } 252 s = s.append(val); 253 if (i == 0) 254 s.append("\n"); 255 } 256 return s.toString(); 257 } 258 259 private String renderType(Type value) throws Exception { 260 String s = null; 261 ByteArrayOutputStream bs = new ByteArrayOutputStream(); 262 if (asXml) { 263 xml.setOutputStyle(OutputStyle.PRETTY); 264 xml.compose(bs, "", value); 265 bs.close(); 266 s = bs.toString(); 267 s = s.substring(s.indexOf("\n")+2); 268 } else { 269 json.setOutputStyle(OutputStyle.PRETTY); 270 json.compose(bs, value, ""); 271 bs.close(); 272 s = bs.toString(); 273 } 274 return s; 275 } 276 277 public void dump() throws IOException { 278 for (CSVLine l : lines) 279 ln(l.toString()); 280 281 flush(); 282 close(); 283 } 284 285}