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