From e73f79103cd5be03242175950a9066d0831090de Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 6 Oct 2022 22:26:36 +1100 Subject: [PATCH] Fix problems in links in bundle rendering --- .../hl7/fhir/r5/renderers/BundleRenderer.java | 29 +++- .../r5/renderers/ProfileDrivenRenderer.java | 7 +- .../fhir/r5/renderers/ResourceRenderer.java | 25 +++- .../r5/renderers/utils/DirectWrappers.java | 4 + .../r5/renderers/utils/ElementWrappers.java | 4 + .../hl7/fhir/r5/renderers/utils/Resolver.java | 126 ++++++++++-------- .../terminologies/JurisdictionUtilities.java | 6 +- 7 files changed, 131 insertions(+), 70 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java index 1a28531b8..4177795e2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java @@ -79,8 +79,13 @@ public class BundleRenderer extends ResourceRenderer { if (be.has("fullUrl")) { root.an(makeInternalBundleLink(be.get("fullUrl").primitiveValue())); } - if (be.has("resource") && be.getChildByName("resource").getValues().get(0).has("id")) { - root.an(be.get("resource").fhirType() + "_" + be.getChildByName("resource").getValues().get(0).get("id").primitiveValue()); + if (be.has("resource")) { + if (be.getChildByName("resource").getValues().get(0).has("id")) { + root.an(be.get("resource").fhirType() + "_" + be.getChildByName("resource").getValues().get(0).get("id").primitiveValue()); + } else { + String id = makeIdFromBundleEntry(be.get("fullUrl").primitiveValue()); + root.an(be.get("resource").fhirType() + "_" + id); + } } root.hr(); if (be.has("fullUrl")) { @@ -101,6 +106,7 @@ public class BundleRenderer extends ResourceRenderer { if (xn == null || xn.isEmpty()) { ResourceRenderer rr = RendererFactory.factory(rw, context); try { + rr.setRcontext(new ResourceContext(rcontext, rw)); xn = rr.render(rw); } catch (Exception e) { xn = new XhtmlNode(); @@ -128,7 +134,7 @@ public class BundleRenderer extends ResourceRenderer { if (subject.hasNarrative()) { x.addChildren(subject.getNarrative()); } else { - RendererFactory.factory(subject, context).render(x, subject); + RendererFactory.factory(subject, context, new ResourceContext(rcontext, subject)).render(x, subject); } } x.hr(); @@ -204,12 +210,14 @@ public class BundleRenderer extends ResourceRenderer { if (nx != null && !nx.isEmpty()) { x.addChildren(nx); } else { - RendererFactory.factory(subject, context).render(x, subject); + RendererFactory.factory(subject, context).setRcontext(new ResourceContext(rcontext, subject)).render(x, subject); } } x.hr(); if (!comp.getText().hasDiv()) { - ResourceRenderer rr = RendererFactory.factory(comp, getContext()); rr.render(comp); + ResourceRenderer rr = RendererFactory.factory(comp, getContext()); + rr.setRcontext(new ResourceContext(rcontext, comp)); + rr.render(comp); } if (comp.getText().hasDiv()) { x.addChildren(comp.getText().getDiv()); @@ -292,8 +300,14 @@ public class BundleRenderer extends ResourceRenderer { if (i > start) { if (be.hasFullUrl()) x.an(makeInternalBundleLink(be.getFullUrl())); - if (be.hasResource() && be.getResource().hasId()) - x.an(be.getResource().getResourceType().name() + "_" + be.getResource().getId()); + if (be.hasResource()) { + if (be.getResource().hasId()) { + x.an(be.getResource().getResourceType().name() + "_" + be.getResource().getId()); + } else { + String id = makeIdFromBundleEntry(be.getFullUrl()); + x.an(be.getResource().getResourceType().name() + "_" + id); + } + } x.hr(); if (docMode) { if (be.hasFullUrl() && be.hasResource()) { @@ -329,6 +343,7 @@ public class BundleRenderer extends ResourceRenderer { if (xn == null || xn.isEmpty()) { ResourceRenderer rr = RendererFactory.factory(be.getResource(), context); try { + rr.setRcontext(new ResourceContext(rcontext, be.getResource())); xn = rr.build(be.getResource()); } catch (Exception e) { xn = makeExceptionXhtml(e, "generating narrative"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index ba060dfe6..e876d539b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -381,7 +381,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { renderContactPoint(x, c); } } else if (e instanceof UriType) { - renderUri(x, (UriType) e, defn.getPath(), rcontext != null && rcontext.getResourceResource() != null ? rcontext.getResourceResource().getId() : null); + renderUri(x, (UriType) e, defn.getPath(), rcontext != null && rcontext.getResource() != null ? rcontext.getResource().getId() : null); } else if (e instanceof Timing) { renderTiming(x, (Timing) e); } else if (e instanceof Range) { @@ -418,6 +418,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { ctxtc.setAddGeneratedNarrativeHeader(false); ctxtc.setContained(true); ResourceRenderer rr = RendererFactory.factory(rw, ctxtc); + rr.setRcontext(new ResourceContext(rcontext, rw)); rr.render(parent.blockquote(), rw); } else { x.ah(ref).tx("See "+rw.fhirType()); @@ -690,12 +691,12 @@ public class ProfileDrivenRenderer extends ResourceRenderer { x.para().b().tx("Generated Narrative: "+profile.present()+(showCodeDetails ? " with Details" : "")); } try { - generateByProfile(rcontext.getResourceResource(), profile, rcontext.getResourceResource(), profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile, profile.getSnapshot().getElement(), rcontext.getResourceResource().getResourceType().toString()), x, rcontext.getResourceResource().getResourceType().toString(), showCodeDetails); + generateByProfile(rcontext.getResource(), profile, rcontext.getResource(), profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile, profile.getSnapshot().getElement(), rcontext.getResource().getResourceType().toString()), x, rcontext.getResource().getResourceType().toString(), showCodeDetails); } catch (Exception e) { e.printStackTrace(); x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage()); } - inject(rcontext.getResourceResource(), x, NarrativeStatus.GENERATED); + inject((DomainResource) rcontext.getResource(), x, NarrativeStatus.GENERATED); return true; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java index 9ba121ce7..df0b24eb4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java @@ -61,6 +61,15 @@ public abstract class ResourceRenderer extends DataRenderer { this.rcontext = rcontext; } + public ResourceContext getRcontext() { + return rcontext; + } + + public ResourceRenderer setRcontext(ResourceContext rcontext) { + this.rcontext = rcontext; + return this; + } + public XhtmlNode build(Resource dr) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome { XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); render(x, dr); @@ -324,7 +333,11 @@ public abstract class ResourceRenderer extends DataRenderer { if (rcontext != null) { BundleEntryComponent bundleResource = rcontext.resolve(url); if (bundleResource != null) { - String bundleUrl = "#" + bundleResource.getResource().getResourceType().name() + "_" + bundleResource.getResource().getId(); + String id = bundleResource.getResource().getId(); + if (id == null) { + id = makeIdFromBundleEntry(bundleResource.getFullUrl()); + } + String bundleUrl = "#" + bundleResource.getResource().getResourceType().name() + "_" + id; return new ResourceWithReference(bundleUrl, new ResourceWrapperDirect(this.context, bundleResource.getResource())); } org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version); @@ -350,6 +363,16 @@ public abstract class ResourceRenderer extends DataRenderer { } + protected String makeIdFromBundleEntry(String url) { + if (url == null) { + return null; + } + if (url.startsWith("urn:uuid:")) { + return url.substring(9).toLowerCase(); + } + return fullUrlToAnchor(url); + } + private String fullUrlToAnchor(String url) { return url.replace(":", "").replace("/", "_"); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java index 8b036031f..88e3819ee 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java @@ -299,6 +299,10 @@ public class DirectWrappers { return new PropertyWrapperDirect(context, p); } + public Resource getResource() { + return wrapped; + } + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java index 45a835ab8..5765a627b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java @@ -286,6 +286,10 @@ public class ElementWrappers { return null; } + public Element getElement() { + return wrapped; + } + } public static class PropertyWrapperMetaElement extends RendererWrapperImpl implements PropertyWrapper { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java index 40b0b12c2..724466b3f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java @@ -7,15 +7,10 @@ import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContextType; import org.w3c.dom.Element; public class Resolver { - public enum ResourceContextType { - PARAMETERS, BUNDLE - } - public interface IReferenceResolver { ResourceWithReference resolve(RenderingContext context, String url); @@ -24,27 +19,24 @@ public class Resolver { } public static class ResourceContext { - private ResourceContextType type; - private Resource containerResource; - private org.hl7.fhir.r5.elementmodel.Element containerElement; + private ResourceContext container; - DomainResource resourceResource; - org.hl7.fhir.r5.elementmodel.Element resourceElement; + Resource resource; + org.hl7.fhir.r5.elementmodel.Element element; - public ResourceContext(ResourceContextType type, Resource bundle, DomainResource dr) { + public ResourceContext(ResourceContext container, Resource dr) { super(); - this.type = type; - this.containerResource = bundle; - this.resourceResource = dr; + this.container = container; + this.resource = dr; } - public ResourceContext(ResourceContextType type, org.hl7.fhir.r5.elementmodel.Element bundle, org.hl7.fhir.r5.elementmodel.Element dr) { + public ResourceContext(ResourceContext container, org.hl7.fhir.r5.elementmodel.Element dr) { super(); - this.type = type; - this.containerElement = bundle; - this.resourceElement = dr; + this.container = container; + this.element = dr; } + // public ResourceContext(Object bundle, Element doc) { // // TODO Auto-generated constructor stub // } @@ -54,22 +46,45 @@ public class Resolver { // } + public ResourceContext(ResourceContext container, ResourceWrapper rw) { + super(); + this.container = container; + // todo: howto do this better? + + if (rw instanceof DirectWrappers.ResourceWrapperDirect) { + this.resource = ((DirectWrappers.ResourceWrapperDirect) rw).getResource(); + } else if (rw instanceof ElementWrappers.ResourceWrapperMetaElement) { + this.element = ((ElementWrappers.ResourceWrapperMetaElement) rw).getElement(); + } else { + throw new Error("Not supported yet"); + } + } + + public ResourceContext getContainer() { + return container; + } + + public void setContainer(ResourceContext container) { + this.container = container; + } + // public org.hl7.fhir.r5.elementmodel.Element getBundleElement() { // return containerElement; // } // - public DomainResource getResourceResource() { - return resourceResource; + public Resource getResource() { + return resource; } - public org.hl7.fhir.r5.elementmodel.Element getResourceElement() { - return resourceElement; + public org.hl7.fhir.r5.elementmodel.Element getElement() { + return element; } public BundleEntryComponent resolve(String value) { if (value.startsWith("#")) { - if (resourceResource != null) { - for (Resource r : resourceResource.getContained()) { + if (resource instanceof DomainResource) { + DomainResource dr = (DomainResource) resource; + for (Resource r : dr.getContained()) { if (r.getId().equals(value.substring(1))) { BundleEntryComponent be = new BundleEntryComponent(); be.setResource(r); @@ -79,44 +94,45 @@ public class Resolver { } return null; } - if (type == ResourceContextType.BUNDLE) { - if (containerResource != null) { - for (BundleEntryComponent be : ((Bundle) containerResource).getEntry()) { - if (be.getFullUrl().equals(value)) - return be; - if (value.equals(be.getResource().fhirType()+"/"+be.getResource().getId())) - return be; + + if (resource instanceof Bundle) { + Bundle b = (Bundle) resource; + for (BundleEntryComponent be : b.getEntry()) { + if (be.getFullUrl().equals(value)) + return be; + if (value.equals(be.getResource().fhirType()+"/"+be.getResource().getId())) + return be; + } + } + + if (resource instanceof Parameters) { + Parameters pp = (Parameters) resource; + for (ParametersParameterComponent p : pp.getParameter()) { + if (p.getResource() != null && value.equals(p.getResource().fhirType()+"/"+p.getResource().getId())) { + BundleEntryComponent be = new BundleEntryComponent(); + be.setResource(p.getResource()); + return be; + } - } - } - if (type == ResourceContextType.PARAMETERS) { - if (containerResource != null) { - for (ParametersParameterComponent p : ((Parameters) containerResource).getParameter()) { - if (p.getResource() != null && value.equals(p.getResource().fhirType()+"/"+p.getResource().getId())) { - BundleEntryComponent be = new BundleEntryComponent(); - be.setResource(p.getResource()); - return be; - - } - } - } - } - return null; + } + } + + return container != null ? container.resolve(value) : null; } public org.hl7.fhir.r5.elementmodel.Element resolveElement(String value, String version) { if (value.startsWith("#")) { - if (resourceElement != null) { - for (org.hl7.fhir.r5.elementmodel.Element r : resourceElement.getChildrenByName("contained")) { + if (element != null) { + for (org.hl7.fhir.r5.elementmodel.Element r : element.getChildrenByName("contained")) { if (r.getChildValue("id").equals(value.substring(1))) return r; } } return null; } - if (type == ResourceContextType.BUNDLE) { - if (containerElement != null) { - for (org.hl7.fhir.r5.elementmodel.Element be : containerElement.getChildren("entry")) { + if (element != null) { + if (element.fhirType().equals("Bundle")) { + for (org.hl7.fhir.r5.elementmodel.Element be : element.getChildren("entry")) { org.hl7.fhir.r5.elementmodel.Element res = be.getNamedChild("resource"); if (res != null) { if (value.equals(be.getChildValue("fullUrl"))) { @@ -132,10 +148,8 @@ public class Resolver { } } } - } - if (type == ResourceContextType.PARAMETERS) { - if (containerElement != null) { - for (org.hl7.fhir.r5.elementmodel.Element p : containerElement.getChildren("parameter")) { + if (element.fhirType().equals("Parameters")) { + for (org.hl7.fhir.r5.elementmodel.Element p : element.getChildren("parameter")) { org.hl7.fhir.r5.elementmodel.Element res = p.getNamedChild("resource"); if (res != null && value.equals(res.fhirType()+"/"+res.getChildValue("id"))) { if (checkVersion(version, res)) { @@ -145,7 +159,7 @@ public class Resolver { } } } - return null; + return container != null ? container.resolveElement(value, version) : null; } private boolean checkVersion(String version, org.hl7.fhir.r5.elementmodel.Element res) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/JurisdictionUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/JurisdictionUtilities.java index 4735bf332..71d22a073 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/JurisdictionUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/JurisdictionUtilities.java @@ -11,7 +11,7 @@ public class JurisdictionUtilities { } public static String getJurisdictionFromLocale(String s) { - if (Utilities.existsInList(s, + if (Utilities.existsInList(s.toUpperCase(), "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", @@ -41,7 +41,7 @@ public class JurisdictionUtilities { "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW" )) { - return "urn:iso:std:iso:3166#"+s; + return "urn:iso:std:iso:3166#"+s.toUpperCase(); } else { switch (s) { case "uv" : return "http://unstats.un.org/unsd/methods/m49/m49.htm#001"; @@ -54,7 +54,7 @@ public class JurisdictionUtilities { } public static String displayJurisdiction(String s) { - return displayJurisdiction(CodeSystemUtilities.readCoding(s)); + return displayJurisdiction(CodeSystemUtilities.readCoding(getJurisdictionFromLocale(s))); } public static String displayJurisdiction(Coding c) {