improve rendering of contained resources

This commit is contained in:
Grahame Grieve 2020-07-17 13:42:44 +10:00
parent 376e4f0ef1
commit 9bbe5ab5c8
8 changed files with 119 additions and 15 deletions

View File

@ -4,8 +4,10 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.NotImplementedException; 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.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; 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.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus; import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
@ -78,6 +81,7 @@ import org.w3c.dom.Element;
public class ProfileDrivenRenderer extends ResourceRenderer { public class ProfileDrivenRenderer extends ResourceRenderer {
private Set<String> containedIds = new HashSet<>();
public ProfileDrivenRenderer(RenderingContext context, ResourceContext rcontext) { public ProfileDrivenRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext); super(context, rcontext);
@ -94,14 +98,17 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
@Override @Override
public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 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 { try {
StructureDefinition sd = r.getDefinition(); StructureDefinition sd = r.getDefinition();
ElementDefinition ed = sd.getSnapshot().getElement().get(0); ElementDefinition ed = sd.getSnapshot().getElement().get(0);
if (sd.getType().equals("NamingSystem") && "icd10".equals(r.getId())) { if (sd.getType().equals("NamingSystem") && "icd10".equals(r.getId())) {
System.out.println("hah!"); 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) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -206,7 +213,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
} }
x.tx("Generated Summary: "); x.tx("Generated Summary: ");
} }
String path = res.getName(); String path = res.fhirType();
StructureDefinition profile = getContext().getWorker().fetchResource(StructureDefinition.class, path); StructureDefinition profile = getContext().getWorker().fetchResource(StructureDefinition.class, path);
if (profile == null) if (profile == null)
x.tx("unknown resource " +path); x.tx("unknown resource " +path);
@ -263,7 +270,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
return null; return null;
} }
private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map<String, String> 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<String, String> displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome {
if (ew == null) if (ew == null)
return; return;
@ -338,7 +345,28 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
renderPeriod(x, p); renderPeriod(x, p);
} else if (e instanceof Reference) { } else if (e instanceof Reference) {
Reference r = (Reference) e; 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) { } else if (e instanceof Resource) {
return; return;
} else if (e instanceof ElementDefinition) { } else if (e instanceof ElementDefinition) {
@ -551,7 +579,9 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
private boolean generateByProfile(StructureDefinition profile, boolean showCodeDetails) { private boolean generateByProfile(StructureDefinition profile, boolean showCodeDetails) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); 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 { 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); 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) { } catch (Exception e) {
@ -562,11 +592,11 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
return true; return true;
} }
private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException { private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> 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); 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<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException { private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome {
if (children.isEmpty()) { if (children.isEmpty()) {
renderLeaf(res, e, defn, x, false, showCodeDetails, readDisplayHints(defn), path, indent); renderLeaf(res, e, defn, x, false, showCodeDetails, readDisplayHints(defn), path, indent);
} else { } else {
@ -575,11 +605,18 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
ElementDefinition child = getElementDefinition(children, path+"."+p.getName(), p); ElementDefinition child = getElementDefinition(children, path+"."+p.getName(), p);
if (child != null) { if (child != null) {
Map<String, String> displayHints = readDisplayHints(child); Map<String, String> 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<ElementDefinition> grandChildren = getChildrenForPath(allElements, path+"."+p.getName()); List<ElementDefinition> grandChildren = getChildrenForPath(allElements, path+"."+p.getName());
filterGrandChildren(grandChildren, path+"."+p.getName(), p); filterGrandChildren(grandChildren, path+"."+p.getName(), p);
if (p.getValues().size() > 0 && child != null) { if (p.getValues().size() > 0) {
if (isPrimitive(child)) { if (isPrimitive(child)) {
XhtmlNode para = x.para(); XhtmlNode para = x.para();
String name = p.getName(); String name = p.getName();
if (name.endsWith("[x]")) if (name.endsWith("[x]"))
@ -691,7 +728,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
tr.td().b().addText(Utilities.capitalize(tail(e.getPath()))); tr.td().b().addText(Utilities.capitalize(tail(e.getPath())));
} }
private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException { private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome {
for (ElementDefinition e : grandChildren) { for (ElementDefinition e : grandChildren) {
PropertyWrapper p = v.getChildByName(e.getPath().substring(e.getPath().lastIndexOf(".")+1)); PropertyWrapper p = v.getChildByName(e.getPath().substring(e.getPath().lastIndexOf(".")+1));
if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null) if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null)

View File

@ -137,6 +137,7 @@ public abstract class ResourceRenderer extends DataRenderer {
else else
c = x.ah(r.getReference()); c = x.ah(r.getReference());
} else { } else {
c = x.ah(r.getReference()); c = x.ah(r.getReference());
} }
} else { } else {

View File

@ -30,6 +30,7 @@ public class BaseWrappers {
public StructureDefinition getStructure(); public StructureDefinition getStructure();
public BaseWrapper value(); public BaseWrapper value();
public ResourceWrapper getAsResource(); public ResourceWrapper getAsResource();
public String fhirType();
} }
public interface WrapperBase extends RendererWrapper { public interface WrapperBase extends RendererWrapper {
@ -37,6 +38,7 @@ public class BaseWrappers {
public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException; public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException;
public List<BaseWrapper> children(String name) throws UnsupportedEncodingException, FHIRException, IOException; public List<BaseWrapper> children(String name) throws UnsupportedEncodingException, FHIRException, IOException;
public List<PropertyWrapper> children(); public List<PropertyWrapper> children();
public String fhirType();
} }
public interface ResourceWrapper extends WrapperBase { public interface ResourceWrapper extends WrapperBase {
@ -55,6 +57,7 @@ public class BaseWrappers {
public interface BaseWrapper extends WrapperBase { public interface BaseWrapper extends WrapperBase {
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException; public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException;
public PropertyWrapper getChildByName(String tail); public PropertyWrapper getChildByName(String tail);
public String fhirType();
} }
public static abstract class RendererWrapperImpl implements RendererWrapper { public static abstract class RendererWrapperImpl implements RendererWrapper {

View File

@ -86,6 +86,11 @@ public class DOMWrappers {
return null; return null;
} }
@Override
public String fhirType() {
return type;
}
} }
public static class PropertyWrapperElement extends RendererWrapperImpl implements PropertyWrapper { public static class PropertyWrapperElement extends RendererWrapperImpl implements PropertyWrapper {
@ -196,6 +201,11 @@ public class DOMWrappers {
throw new Error("Not implemented yet"); throw new Error("Not implemented yet");
} }
@Override
public String fhirType() {
return getTypeCode();
}
} }
public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper { public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper {
@ -342,6 +352,11 @@ public class DOMWrappers {
} }
return false; return false;
} }
@Override
public String fhirType() {
return wrapped.getNodeName();
}
} }
} }

View File

@ -101,6 +101,11 @@ public class DirectWrappers {
public ResourceWrapper getAsResource() { public ResourceWrapper getAsResource() {
throw new Error("Not implemented yet"); throw new Error("Not implemented yet");
} }
@Override
public String fhirType() {
return wrapped.getTypeCode();
}
} }
public static class BaseWrapperDirect extends WrapperBaseImpl implements BaseWrapper { public static class BaseWrapperDirect extends WrapperBaseImpl implements BaseWrapper {
@ -139,6 +144,11 @@ public class DirectWrappers {
return new PropertyWrapperDirect(context, p); return new PropertyWrapperDirect(context, p);
} }
@Override
public String fhirType() {
return wrapped.fhirType();
}
} }
public static class ResourceWrapperDirect extends WrapperBaseImpl implements ResourceWrapper { public static class ResourceWrapperDirect extends WrapperBaseImpl implements ResourceWrapper {
@ -237,6 +247,11 @@ public class DirectWrappers {
return false; return false;
} }
@Override
public String fhirType() {
return wrapped.fhirType();
}
} }
} }

View File

@ -97,6 +97,11 @@ public class ElementWrappers {
return null; return null;
} }
@Override
public String fhirType() {
return element.fhirType();
}
} }
public static class ResourceWrapperMetaElement extends WrapperBaseImpl implements ResourceWrapper { public static class ResourceWrapperMetaElement extends WrapperBaseImpl implements ResourceWrapper {
@ -236,6 +241,11 @@ public class ElementWrappers {
} }
return false; return false;
} }
@Override
public String fhirType() {
return wrapped.fhirType();
}
} }
public static class PropertyWrapperMetaElement extends RendererWrapperImpl implements PropertyWrapper { public static class PropertyWrapperMetaElement extends RendererWrapperImpl implements PropertyWrapper {
@ -309,6 +319,11 @@ public class ElementWrappers {
return new ElementWrappers.ResourceWrapperMetaElement(context, values.get(0)); return new ElementWrappers.ResourceWrapperMetaElement(context, values.get(0));
} }
@Override
public String fhirType() {
return getTypeCode();
}
} }
} }

View File

@ -94,6 +94,7 @@ public class RenderingContext {
private boolean inlineGraphics; private boolean inlineGraphics;
private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM; private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM;
private boolean addGeneratedNarrativeHeader = true;
/** /**
* *
@ -321,7 +322,8 @@ public class RenderingContext {
res.profileUtilities = profileUtilities; res.profileUtilities = profileUtilities;
res.definitionsTarget = definitionsTarget; res.definitionsTarget = definitionsTarget;
res.destDir = destDir; res.destDir = destDir;
res.addGeneratedNarrativeHeader = addGeneratedNarrativeHeader;
return res; return res;
} }
@ -381,6 +383,16 @@ public class RenderingContext {
return this; return this;
} }
public boolean isAddGeneratedNarrativeHeader() {
return addGeneratedNarrativeHeader;
}
public RenderingContext setAddGeneratedNarrativeHeader(boolean addGeneratedNarrativeHeader) {
this.addGeneratedNarrativeHeader = addGeneratedNarrativeHeader;
return this;
}
} }

View File

@ -571,8 +571,14 @@ public class XhtmlNode implements IBaseXhtml {
return addTag("img").attribute("src", src).attribute("title", title); return addTag("img").attribute("src", src).attribute("title", title);
} }
public void an(String href) { public XhtmlNode an(String href) {
addTag("a").attribute("name", href).tx(" "); 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) { public XhtmlNode span(String style, String title) {