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