001package org.hl7.fhir.convertors.misc; 002 003import java.io.File; 004import java.io.FileNotFoundException; 005import java.io.FileOutputStream; 006import java.io.IOException; 007import java.util.ArrayList; 008import java.util.HashSet; 009import java.util.Set; 010 011import org.hl7.fhir.exceptions.FHIRFormatError; 012import org.hl7.fhir.r5.context.CanonicalResourceManager; 013import org.hl7.fhir.r5.formats.IParser.OutputStyle; 014import org.hl7.fhir.r5.formats.JsonParser; 015import org.hl7.fhir.r5.formats.XmlParser; 016import org.hl7.fhir.r5.model.CanonicalResource; 017import org.hl7.fhir.r5.model.CodeSystem; 018import org.hl7.fhir.r5.model.ElementDefinition; 019import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; 020import org.hl7.fhir.r5.model.StructureDefinition; 021import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionContextComponent; 022import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; 023import org.hl7.fhir.r5.model.ValueSet; 024import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 025import org.hl7.fhir.utilities.Utilities; 026import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 027import org.hl7.fhir.utilities.json.model.JsonObject; 028import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; 029import org.hl7.fhir.utilities.npm.NpmPackage; 030import org.hl7.fhir.utilities.xml.XMLUtil; 031import org.w3c.dom.Element; 032 033public class ExtensionExtractor { 034 035 public static void main(String[] args) throws FHIRFormatError, FileNotFoundException, IOException { 036 new ExtensionExtractor().process(args[0]); 037 } 038 039 private void process(String dst) throws IOException { 040 Set<String> ids = new HashSet<>(); 041 FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().build(); 042 NpmPackage r5 = pcm.loadPackage("hl7.fhir.r5.core", "current"); 043 CanonicalResourceManager<CodeSystem> cslist = new CanonicalResourceManager<CodeSystem>(true, false); 044 for (String r : r5.listResources("CodeSystem")) { 045 CodeSystem cs = (CodeSystem) new JsonParser().parse(r5.load(r)); 046 cslist.see(cs, null); 047 } 048 CanonicalResourceManager<ValueSet> vslist = new CanonicalResourceManager<ValueSet>(true, false); 049 for (String r : r5.listResources("ValueSet")) { 050 ValueSet vs = (ValueSet) new JsonParser().parse(r5.load(r)); 051 vslist.see(vs, null); 052 } 053 for (ValueSet vs : vslist.getList()) { 054 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 055 CodeSystem cs = cslist.get(inc.getSystem()); 056 if (cs != null) { 057 if (!cs.hasUserData("vsl")) { 058 cs.setUserData("vsl", new ArrayList<ValueSet>()); 059 } 060 ((ArrayList<ValueSet>) cs.getUserData("vsl")).add(vs); 061 } 062 } 063 } 064 for (String r : r5.listResources("StructureDefinition")) { 065 StructureDefinition sd = (StructureDefinition) new JsonParser().parse(r5.load(r)); 066 if (sd.getType().equals("Extension") && sd.getDerivation() == TypeDerivationRule.CONSTRAINT) { 067 for (ElementDefinition ed : sd.getSnapshot().getElement()) { 068 seeBinding(ed.getBinding().getValueSet(), vslist, "ext", sd); 069 for (ElementDefinitionBindingAdditionalComponent ab : ed.getBinding().getAdditional()) { 070 seeBinding(ab.getValueSet(), vslist, "ext", sd); 071 } 072 } 073 sd.setSnapshot(null); 074 String fn; 075 if (sd.getContext().size() == 0) { 076 save(sd, dst,"none", ids); 077 } else if (sd.getContext().size() > 1) { 078 boolean dt = true; 079 for (StructureDefinitionContextComponent x : sd.getContext()) { 080 String s = extractType(x.getExpression()); 081 dt = dt && isDataType(s); 082 } 083 if (dt) { 084 save(sd, dst,"datatypes", ids); 085 } else { 086 save(sd, dst,"multiple", ids); 087 } 088 } else { 089 String s = extractType(sd.getContextFirstRep().getExpression()); 090 if (isDataType(s)) { 091 save(sd, dst,"datatypes", ids); 092 } else { 093 save(sd, dst,s, ids); 094 } 095 } 096 } else { 097 for (ElementDefinition ed : sd.getSnapshot().getElement()) { 098 seeBinding(ed.getBinding().getValueSet(), vslist, "core", sd); 099 for (ElementDefinitionBindingAdditionalComponent ab : ed.getBinding().getAdditional()) { 100 seeBinding(ab.getValueSet(), vslist, "core", sd); 101 } 102 } 103 } 104 } 105 for (ValueSet vs : vslist.getList()) { 106 if (vs.hasUserData("core") || !vs.hasUserData("ext") || vs.getUrl().startsWith("http://terminology.")) { 107 vslist.drop(vs.getId()); 108 } 109 } 110 for (CodeSystem cs : cslist.getList()) { 111 boolean keep = false; 112 if (cs.hasUserData("vsl") && !cs.getUrl().startsWith("http://terminology.")) { 113 keep = true; 114 for (ValueSet vs : (ArrayList<ValueSet>) cs.getUserData("vsl")) { 115 if (!vslist.has(vs.getUrl())) { 116 keep = false; 117 } 118 } 119 } 120 if (!keep) { 121 cslist.drop(cs.getId()); 122 } 123 } 124 for (ValueSet vs : vslist.getList()) { 125 StructureDefinition sd = (StructureDefinition) vs.getUserData("ext"); 126 String s = sd.getUserString("folder"); 127 save(vs, dst, s, ids); 128 } 129 for (CodeSystem cs : cslist.getList()) { 130 ValueSet vs = ((ArrayList<ValueSet>) cs.getUserData("vsl")).get(0); 131 String s = vs.getUserString("folder"); 132 save(cs, dst,s, ids); 133 } 134 135 deleteMatchingResources(ids, ManagedFileAccess.file("/Users/grahamegrieve/work/r5/source")); 136 } 137 138 private void deleteMatchingResources(Set<String> ids, File folder) { 139 for (File f : folder.listFiles()) { 140 if (f.isDirectory()) { 141 deleteMatchingResources(ids, f); 142 } else if (f.getName().endsWith(".json")) { 143 try { 144 JsonObject json = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(f); 145 if (json.has("resourceType") && json.has("id") && ids.contains(json.asString("id"))) { 146 System.out.println("Delete "+f.getAbsolutePath()); 147 f.delete(); 148 } 149 } catch (Exception e) { 150 // nothing 151 } 152 } else if (f.getName().endsWith(".xml")) { 153 try { 154 Element xml = XMLUtil.parseFileToDom(f.getAbsolutePath()).getDocumentElement(); 155 if (XMLUtil.hasNamedChild(xml, "id") && ids.contains(XMLUtil.getNamedChildValue(xml, "id"))) { 156 System.out.println("Delete "+f.getAbsolutePath()); 157 f.delete(); 158 } 159 } catch (Exception e) { 160 // nothing 161 } 162 } 163 } 164 165 } 166 167 private void save(CanonicalResource cr, String dst, String folder, Set<String> ids) throws IOException { 168 // TODO Auto-generated method stub 169 cr.setText(null); 170 if (!cr.hasTitle()) { 171 cr.setTitle(Utilities.unCamelCase(cr.getName())); 172 } 173 ids.add(cr.getId()); 174 String fn = Utilities.path(dst, folder, cr.fhirType()+"-"+cr.getId()+".xml"); 175 cr.setUserData("folder", folder); 176 if (!ManagedFileAccess.file(fn).exists()) { 177 Utilities.createDirectory(Utilities.getDirectoryForFile(fn)); 178 new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(fn), cr); 179 } 180 } 181 182 private void seeBinding(String url, CanonicalResourceManager<ValueSet> vslist, String name, StructureDefinition sd) { 183 ValueSet vs = vslist.get(url); 184 if (vs != null) { 185 vs.setUserData(name, sd); 186 } 187 } 188 189 private boolean isDataType(String s) { 190 return Utilities.existsInList(s, 191 "PrimitiveType", "instant", "time", "date", "dateTime", "decimal", "boolean", "integer", "string", 192 "uri", "base64Binary", "code", "id", "oid", "unsignedInt", "positiveInt", "markdown", "url", "canonical", 193 "uuid", "integer64", "DataType", "BackboneType", "Identifier", "HumanName", "Address", "ContactPoint", 194 "Timing", "Quantity", "SimpleQuantity", "Attachment", "Range", "Period", "Ratio", "RatioRange", "CodeableConcept", 195 "Coding", "SampledData", "Age", "Distance", "Duration", "Count", "Money", "MoneyQuantity", "Annotation", "Signature", "DataType", 196 "ContactDetail", "Contributor", "DataRequirement", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext", 197 "Expression", "ExtendedContactDetail", "VirtualServiceDetail", "Availability", "MonetaryComponent", "DataType", 198 "BackboneType", "Reference", "Narrative", "Extension", "Meta", "ElementDefinition", "Dosage", "xhtml", "CodeableReference"); 199 } 200 201 private String extractType(String x) { 202 String s = x; 203 if (s.contains(".")) { 204 s = s.substring(0, s.indexOf(".")); 205 } 206 return s; 207 } 208}