From 9bbe5ab5c82fa08f63b00c62c0abf94a905fb324 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 17 Jul 2020 13:42:44 +1000 Subject: [PATCH] improve rendering of contained resources --- .../r5/renderers/ProfileDrivenRenderer.java | 61 +++++++++++++++---- .../fhir/r5/renderers/ResourceRenderer.java | 1 + .../fhir/r5/renderers/utils/BaseWrappers.java | 3 + .../fhir/r5/renderers/utils/DOMWrappers.java | 15 +++++ .../r5/renderers/utils/DirectWrappers.java | 15 +++++ .../r5/renderers/utils/ElementWrappers.java | 15 +++++ .../r5/renderers/utils/RenderingContext.java | 14 ++++- .../hl7/fhir/utilities/xhtml/XhtmlNode.java | 10 ++- 8 files changed, 119 insertions(+), 15 deletions(-) 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 e0fab8780..f38e9c4a0 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 @@ -4,8 +4,10 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.NotImplementedException; @@ -66,6 +68,7 @@ import org.hl7.fhir.r5.renderers.utils.DirectWrappers.ResourceWrapperDirect; import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; +import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus; @@ -78,6 +81,7 @@ import org.w3c.dom.Element; public class ProfileDrivenRenderer extends ResourceRenderer { + private Set containedIds = new HashSet<>(); public ProfileDrivenRenderer(RenderingContext context, ResourceContext rcontext) { super(context, rcontext); @@ -94,14 +98,17 @@ public class ProfileDrivenRenderer extends ResourceRenderer { @Override public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { - x.para().b().tx("Generated Narrative"); + if (context.isAddGeneratedNarrativeHeader()) { + x.para().b().tx("Generated Narrative"); + } try { StructureDefinition sd = r.getDefinition(); ElementDefinition ed = sd.getSnapshot().getElement().get(0); if (sd.getType().equals("NamingSystem") && "icd10".equals(r.getId())) { System.out.println("hah!"); } - generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.getName(), false, 0); + containedIds.clear(); + generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0); } catch (Exception e) { e.printStackTrace(); @@ -206,7 +213,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } x.tx("Generated Summary: "); } - String path = res.getName(); + String path = res.fhirType(); StructureDefinition profile = getContext().getWorker().fetchResource(StructureDefinition.class, path); if (profile == null) x.tx("unknown resource " +path); @@ -263,7 +270,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { return null; } - private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException { + private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { if (ew == null) return; @@ -338,7 +345,28 @@ public class ProfileDrivenRenderer extends ResourceRenderer { renderPeriod(x, p); } else if (e instanceof Reference) { Reference r = (Reference) e; - renderReference(res, x, r); + if (r.getReference() != null && r.getReference().contains("#")) { + if (containedIds.contains(r.getReference().substring(1))) { + x.ah(r.getReference()).tx("See "+r.getReference()); + } else { + // in this case, we render the resource in line + ResourceWrapper rw = null; + for (ResourceWrapper t : res.getContained()) { + if (r.getReference().substring(1).equals(t.getId())) { + rw = t; + } + } + if (rw == null) { + renderReference(res, x, r); + } else { + x.an(rw.getId()); + ResourceRenderer rr = RendererFactory.factory(rw, context.copy().setAddGeneratedNarrativeHeader(false)); + rr.render(x.blockquote(), rw); + } + } + } else { + renderReference(res, x, r); + } } else if (e instanceof Resource) { return; } else if (e instanceof ElementDefinition) { @@ -551,7 +579,9 @@ public class ProfileDrivenRenderer extends ResourceRenderer { private boolean generateByProfile(StructureDefinition profile, boolean showCodeDetails) { XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - x.para().b().tx("Generated Narrative"+(showCodeDetails ? " with Details" : "")); + if(context.isAddGeneratedNarrativeHeader()) { + x.para().b().tx("Generated Narrative"+(showCodeDetails ? " with Details" : "")); + } try { generateByProfile(rcontext.getResourceResource(), profile, rcontext.getResourceResource(), profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile.getSnapshot().getElement(), rcontext.getResourceResource().getResourceType().toString()), x, rcontext.getResourceResource().getResourceType().toString(), showCodeDetails); } catch (Exception e) { @@ -562,11 +592,11 @@ public class ProfileDrivenRenderer extends ResourceRenderer { return true; } - private void generateByProfile(Resource res, StructureDefinition profile, Base e, List allElements, ElementDefinition defn, List children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException { + private void generateByProfile(Resource res, StructureDefinition profile, Base e, List allElements, ElementDefinition defn, List children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { generateByProfile(new ResourceWrapperDirect(this.context, res), profile, new BaseWrapperDirect(this.context, e), allElements, defn, children, x, path, showCodeDetails, 0); } - private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List allElements, ElementDefinition defn, List children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException { + private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List allElements, ElementDefinition defn, List children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { if (children.isEmpty()) { renderLeaf(res, e, defn, x, false, showCodeDetails, readDisplayHints(defn), path, indent); } else { @@ -575,11 +605,18 @@ public class ProfileDrivenRenderer extends ResourceRenderer { ElementDefinition child = getElementDefinition(children, path+"."+p.getName(), p); if (child != null) { Map displayHints = readDisplayHints(child); - if (!exemptFromRendering(child)) { + if ("DomainResource.contained".equals(child.getBase().getPath())) { +// if (p.getValues().size() > 0 && child != null) { +// for (BaseWrapper v : p.getValues()) { +// x.an(v.get("id").primitiveValue()); +// } +// } + System.out.print("c"); + } else if (!exemptFromRendering(child)) { List grandChildren = getChildrenForPath(allElements, path+"."+p.getName()); filterGrandChildren(grandChildren, path+"."+p.getName(), p); - if (p.getValues().size() > 0 && child != null) { - if (isPrimitive(child)) { + if (p.getValues().size() > 0) { + if (isPrimitive(child)) { XhtmlNode para = x.para(); String name = p.getName(); if (name.endsWith("[x]")) @@ -691,7 +728,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { tr.td().b().addText(Utilities.capitalize(tail(e.getPath()))); } - private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List grandChildren, BaseWrapper v, boolean showCodeDetails, Map displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException { + private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List grandChildren, BaseWrapper v, boolean showCodeDetails, Map displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { for (ElementDefinition e : grandChildren) { PropertyWrapper p = v.getChildByName(e.getPath().substring(e.getPath().lastIndexOf(".")+1)); if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null) 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 55f1c5a64..d494dd9fc 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 @@ -137,6 +137,7 @@ public abstract class ResourceRenderer extends DataRenderer { else c = x.ah(r.getReference()); } else { + c = x.ah(r.getReference()); } } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java index 8ec2d07df..b811ac7fe 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java @@ -30,6 +30,7 @@ public class BaseWrappers { public StructureDefinition getStructure(); public BaseWrapper value(); public ResourceWrapper getAsResource(); + public String fhirType(); } public interface WrapperBase extends RendererWrapper { @@ -37,6 +38,7 @@ public class BaseWrappers { public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException; public List children(String name) throws UnsupportedEncodingException, FHIRException, IOException; public List children(); + public String fhirType(); } public interface ResourceWrapper extends WrapperBase { @@ -55,6 +57,7 @@ public class BaseWrappers { public interface BaseWrapper extends WrapperBase { public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException; public PropertyWrapper getChildByName(String tail); + public String fhirType(); } public static abstract class RendererWrapperImpl implements RendererWrapper { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java index 7e301704b..da7d83da6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java @@ -86,6 +86,11 @@ public class DOMWrappers { return null; } + @Override + public String fhirType() { + return type; + } + } public static class PropertyWrapperElement extends RendererWrapperImpl implements PropertyWrapper { @@ -196,6 +201,11 @@ public class DOMWrappers { throw new Error("Not implemented yet"); } + @Override + public String fhirType() { + return getTypeCode(); + } + } public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper { @@ -342,6 +352,11 @@ public class DOMWrappers { } return false; } + + @Override + public String fhirType() { + return wrapped.getNodeName(); + } } } \ No newline at end of file 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 4a4e311bb..3cbe12568 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 @@ -101,6 +101,11 @@ public class DirectWrappers { public ResourceWrapper getAsResource() { throw new Error("Not implemented yet"); } + + @Override + public String fhirType() { + return wrapped.getTypeCode(); + } } public static class BaseWrapperDirect extends WrapperBaseImpl implements BaseWrapper { @@ -139,6 +144,11 @@ public class DirectWrappers { return new PropertyWrapperDirect(context, p); } + @Override + public String fhirType() { + return wrapped.fhirType(); + } + } public static class ResourceWrapperDirect extends WrapperBaseImpl implements ResourceWrapper { @@ -237,6 +247,11 @@ public class DirectWrappers { return false; } + + @Override + public String fhirType() { + return wrapped.fhirType(); + } } } \ 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 1e1194715..b21cd002b 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 @@ -97,6 +97,11 @@ public class ElementWrappers { return null; } + @Override + public String fhirType() { + return element.fhirType(); + } + } public static class ResourceWrapperMetaElement extends WrapperBaseImpl implements ResourceWrapper { @@ -236,6 +241,11 @@ public class ElementWrappers { } return false; } + + @Override + public String fhirType() { + return wrapped.fhirType(); + } } public static class PropertyWrapperMetaElement extends RendererWrapperImpl implements PropertyWrapper { @@ -309,6 +319,11 @@ public class ElementWrappers { return new ElementWrappers.ResourceWrapperMetaElement(context, values.get(0)); } + @Override + public String fhirType() { + return getTypeCode(); + } + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java index 94a24bffc..fa2342b1a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java @@ -94,6 +94,7 @@ public class RenderingContext { private boolean inlineGraphics; private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM; + private boolean addGeneratedNarrativeHeader = true; /** * @@ -321,7 +322,8 @@ public class RenderingContext { res.profileUtilities = profileUtilities; res.definitionsTarget = definitionsTarget; res.destDir = destDir; - + res.addGeneratedNarrativeHeader = addGeneratedNarrativeHeader; + return res; } @@ -381,6 +383,16 @@ public class RenderingContext { return this; } + public boolean isAddGeneratedNarrativeHeader() { + return addGeneratedNarrativeHeader; + } + + public RenderingContext setAddGeneratedNarrativeHeader(boolean addGeneratedNarrativeHeader) { + this.addGeneratedNarrativeHeader = addGeneratedNarrativeHeader; + return this; + } + + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java index 9177e3dde..67c998c4b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java @@ -571,8 +571,14 @@ public class XhtmlNode implements IBaseXhtml { return addTag("img").attribute("src", src).attribute("title", title); } - public void an(String href) { - addTag("a").attribute("name", href).tx(" "); + public XhtmlNode an(String href) { + return an(href, " "); + } + + public XhtmlNode an(String href, String tx) { + XhtmlNode a = addTag("a").attribute("name", href); + a.tx(tx); + return a; } public XhtmlNode span(String style, String title) {