
001package org.hl7.fhir.r5.renderers; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005import java.util.ArrayList; 006import java.util.List; 007import java.util.Map; 008 009import org.hl7.fhir.exceptions.DefinitionException; 010import org.hl7.fhir.exceptions.FHIRFormatError; 011import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; 012import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; 013import org.hl7.fhir.r5.model.CanonicalResource; 014import org.hl7.fhir.r5.model.CodeSystem; 015import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; 016import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent; 017import org.hl7.fhir.r5.model.ConceptMap; 018import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent; 019import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent; 020import org.hl7.fhir.r5.model.ConceptMap.TargetElementComponent; 021import org.hl7.fhir.r5.model.DomainResource; 022import org.hl7.fhir.r5.model.Questionnaire; 023import org.hl7.fhir.r5.model.Resource; 024import org.hl7.fhir.r5.model.StructureDefinition; 025import org.hl7.fhir.r5.model.ValueSet; 026import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 027import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; 028import org.hl7.fhir.r5.renderers.utils.RenderingContext; 029import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; 030import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; 031import org.hl7.fhir.r5.utils.ToolingExtensions; 032import org.hl7.fhir.utilities.Utilities; 033import org.hl7.fhir.utilities.xhtml.XhtmlNode; 034 035public abstract class TerminologyRenderer extends ResourceRenderer { 036 037 public TerminologyRenderer(RenderingContext context) { 038 super(context); 039 } 040 041 public TerminologyRenderer(RenderingContext context, ResourceContext rcontext) { 042 super(context, rcontext); 043 } 044 045 public String display(Resource r) throws UnsupportedEncodingException, IOException { 046 return ((CanonicalResource) r).present(); 047 } 048 049 public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 050 if (r.has("title")) { 051 return r.children("title").get(0).getBase().primitiveValue(); 052 } 053 if (r.has("name")) { 054 return r.children("name").get(0).getBase().primitiveValue(); 055 } 056 return "??"; 057 } 058 059 protected class TargetElementComponentWrapper { 060 protected ConceptMapGroupComponent group; 061 protected TargetElementComponent comp; 062 protected TargetElementComponentWrapper(ConceptMapGroupComponent group, TargetElementComponent comp) { 063 super(); 064 this.group = group; 065 this.comp = comp; 066 } 067 068 } 069 070 public class UsedConceptMap { 071 072 private ConceptMapRenderInstructions details; 073 private String link; 074 private ConceptMap map; 075 public UsedConceptMap(ConceptMapRenderInstructions details, String link, ConceptMap map) { 076 super(); 077 this.details = details; 078 this.link = link; 079 this.map = map; 080 } 081 public ConceptMapRenderInstructions getDetails() { 082 return details; 083 } 084 public ConceptMap getMap() { 085 return map; 086 } 087 public String getLink() { 088 return link; 089 } 090 } 091 092 public class ConceptMapRenderInstructions { 093 private String name; 094 private String url; 095 private boolean doDescription; 096 public ConceptMapRenderInstructions(String name, String url, boolean doDescription) { 097 super(); 098 this.name = name; 099 this.url = url; 100 this.doDescription = doDescription; 101 } 102 public String getName() { 103 return name; 104 } 105 public String getUrl() { 106 return url; 107 } 108 public boolean isDoDescription() { 109 return doDescription; 110 } 111 } 112 113 114 protected void addMapHeaders(XhtmlNode tr, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException { 115 for (UsedConceptMap m : maps) { 116 XhtmlNode td = tr.td(); 117 XhtmlNode b = td.b(); 118 XhtmlNode a = b.ah(getContext().getSpecificationLink()+m.getLink()); 119 a.addText(m.getDetails().getName()); 120 if (m.getDetails().isDoDescription() && m.getMap().hasDescription()) 121 addMarkdown(td, m.getMap().getDescription()); 122 } 123 } 124 125 protected String getHeader() { 126 int i = 3; 127 while (i <= getContext().getHeaderLevelContext()) 128 i++; 129 if (i > 6) 130 i = 6; 131 return "h"+Integer.toString(i); 132 } 133 134 protected List<TargetElementComponentWrapper> findMappingsForCode(String code, ConceptMap map) { 135 List<TargetElementComponentWrapper> mappings = new ArrayList<TargetElementComponentWrapper>(); 136 137 for (ConceptMapGroupComponent g : map.getGroup()) { 138 for (SourceElementComponent c : g.getElement()) { 139 if (c.getCode().equals(code)) 140 for (TargetElementComponent cc : c.getTarget()) 141 mappings.add(new TargetElementComponentWrapper(g, cc)); 142 } 143 } 144 return mappings; 145 } 146 147 148 149 protected String getCharForRelationship(TargetElementComponent mapping) { 150 if (!mapping.hasRelationship()) 151 return ""; 152 switch (mapping.getRelationship()) { 153 case EQUIVALENT : return "~"; 154 case SOURCEISNARROWERTHANTARGET : return "<"; 155 case SOURCEISBROADERTHANTARGET : return ">"; 156 case NOTRELATEDTO : return "!="; 157 default: return "?"; 158 } 159 } 160 161 protected <T extends Resource> void addCsRef(ConceptSetComponent inc, XhtmlNode li, T cs) { 162 String ref = null; 163 boolean addHtml = true; 164 if (cs != null) { 165 ref = (String) cs.getUserData("external.url"); 166 if (Utilities.noString(ref)) 167 ref = (String) cs.getUserData("filename"); 168 else 169 addHtml = false; 170 if (Utilities.noString(ref)) { 171 ref = (String) cs.getUserData("path"); 172 if (ref != null) { 173 addHtml = false; 174 } 175 } 176 } 177 String spec = getSpecialReference(inc.getSystem()); 178 if (spec != null) { 179 XhtmlNode a = li.ah(spec); 180 a.code(inc.getSystem()); 181 } else if (cs != null && ref != null) { 182 if (addHtml && !ref.contains(".html")) 183 ref = ref + ".html"; 184 ref = context.fixReference(ref); 185 XhtmlNode a = li.ah(ref.replace("\\", "/")); 186 a.code(inc.getSystem()); 187 } else { 188 li.code(inc.getSystem()); 189 } 190 } 191 192 193 private String getSpecialReference(String system) { 194 if ("http://snomed.info/sct".equals(system)) 195 return "http://www.snomed.org/"; 196 if (Utilities.existsInList(system, "http://loinc.org", "http://unitsofmeasure.org", "http://www.nlm.nih.gov/research/umls/rxnorm", "http://ncimeta.nci.nih.gov", "http://fdasis.nlm.nih.gov", 197 "http://www.radlex.org", "http://www.whocc.no/atc", "http://dicom.nema.org/resources/ontology/DCM", "http://www.genenames.org", "http://www.ensembl.org", "http://www.ncbi.nlm.nih.gov/nuccore", 198 "http://www.ncbi.nlm.nih.gov/clinvar", "http://sequenceontology.org", "http://www.hgvs.org/mutnomen", "http://www.ncbi.nlm.nih.gov/projects/SNP", "http://cancer.sanger.ac.uk/cancergenome/projects/cosmic", 199 "http://www.lrg-sequence.org", "http://www.omim.org", "http://www.ncbi.nlm.nih.gov/pubmed", "http://www.pharmgkb.org", "http://clinicaltrials.gov", "http://www.ebi.ac.uk/ipd/imgt/hla/")) 200 return system; 201 202 return null; 203 } 204 205 protected XhtmlNode addTableHeaderRowStandard(XhtmlNode t, boolean hasHierarchy, boolean hasDisplay, boolean definitions, boolean comments, boolean version, boolean deprecated, List<PropertyComponent> properties, List<String> langs, Map<String, String> designations, boolean doDesignations) { 206 XhtmlNode tr = t.tr(); 207 if (hasHierarchy) { 208 tr.td().b().tx("Lvl"); 209 } 210 tr.td().attribute("style", "white-space:nowrap").b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang())); 211 if (hasDisplay) { 212 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Display", getContext().getLang())); 213 } 214 if (definitions) { 215 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Definition", getContext().getLang())); 216 } 217 if (deprecated) { 218 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Deprecated", getContext().getLang())); 219 } 220 if (comments) { 221 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Comments", getContext().getLang())); 222 } 223 if (version) { 224 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Version", getContext().getLang())); 225 } 226 if (properties != null) { 227 for (PropertyComponent pc : properties) { 228 String display = ToolingExtensions.getPresentation(pc, pc.getCodeElement()); 229 if (display == null || display.equals(pc.getCode()) && pc.hasUri()) { 230 display = getDisplayForProperty(pc.getUri()); 231 if (display == null) { 232 display = pc.getCode(); 233 } 234 } 235 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", display, getContext().getLang())); 236 } 237 } 238 if (doDesignations) { 239 for (String url : designations.keySet()) { 240 tr.td().b().addText(designations.get(url)); 241 } 242 for (String lang : langs) { 243 tr.td().b().addText(describeLang(lang)); 244 } 245 } 246 return tr; 247 } 248 249 250 protected String getDisplayForProperty(String uri) { 251 if (Utilities.noString(uri)){ 252 return null; 253 } 254 String code = null; 255 if (uri.contains("#")) { 256 code = uri.substring(uri.indexOf("#")+1); 257 uri = uri.substring(0, uri.indexOf("#")); 258 } 259 CodeSystem cs = getContext().getWorker().fetchCodeSystem(uri); 260 if (cs == null) { 261 return null; 262 } 263 ConceptDefinitionComponent cc = code == null ? null : CodeSystemUtilities.getCode(cs, code); 264 return cc == null ? null : cc.getDisplay(); 265 } 266 267 268 protected void AddVsRef(String value, XhtmlNode li) { 269 Resource res = null; 270 if (rcontext != null) { 271 BundleEntryComponent be = rcontext.resolve(value); 272 if (be != null) { 273 res = be.getResource(); 274 } 275 } 276 if (res != null && !(res instanceof CanonicalResource)) { 277 li.addText(value); 278 return; 279 } 280 CanonicalResource vs = (CanonicalResource) res; 281 if (vs == null) 282 vs = getContext().getWorker().fetchResource(ValueSet.class, value); 283 if (vs == null) 284 vs = getContext().getWorker().fetchResource(StructureDefinition.class, value); 285 // if (vs == null) 286 // vs = context.getWorker().fetchResource(DataElement.class, value); 287 if (vs == null) 288 vs = getContext().getWorker().fetchResource(Questionnaire.class, value); 289 if (vs != null) { 290 String ref = (String) vs.getUserData("path"); 291 292 ref = context.fixReference(ref); 293 XhtmlNode a = li.ah(ref == null ? "?ngen-11?" : ref.replace("\\", "/")); 294 a.addText(value); 295 } else { 296 CodeSystem cs = getContext().getWorker().fetchCodeSystem(value); 297 if (cs != null) { 298 String ref = (String) cs.getUserData("path"); 299 ref = context.fixReference(ref); 300 XhtmlNode a = li.ah(ref == null ? "?ngen-12?" : ref.replace("\\", "/")); 301 a.addText(value); 302 } else if (value.equals("http://snomed.info/sct") || value.equals("http://snomed.info/id")) { 303 XhtmlNode a = li.ah(value); 304 a.tx("SNOMED-CT"); 305 } 306 else { 307 if (value.startsWith("http://hl7.org") && !Utilities.existsInList(value, "http://hl7.org/fhir/sid/icd-10-us")) 308 System.out.println("Unable to resolve value set "+value); 309 li.addText(value); 310 } 311 } 312 } 313 314 315 316 protected String getDisplayForConcept(String system, String version, String value) { 317 if (value == null || system == null) 318 return null; 319 ValidationResult cl = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions().setVersionFlexible(true), system, version, value, null); 320 return cl == null ? null : cl.getDisplay(); 321 } 322 323}