WIP: rewrite of rendering framework

This commit is contained in:
Grahame Grieve 2024-06-13 07:38:22 +10:00
parent 7d0c63611f
commit 506dad8752
10 changed files with 1225 additions and 921 deletions

View File

@ -150,6 +150,11 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
public boolean render(XhtmlNode x, DiagnosticReport dr) throws IOException, FHIRException, EOperationOutcome { public boolean render(XhtmlNode x, DiagnosticReport dr) throws IOException, FHIRException, EOperationOutcome {
render(x, new DirectWrappers.ResourceWrapperDirect(this.context, dr)); render(x, new DirectWrappers.ResourceWrapperDirect(this.context, dr));
for (Resource resource : dr.getContained()) {
x.hr();
RendererFactory.factory(resource, context).render(x, resource);
}
return true; return true;
} }
@ -461,7 +466,9 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
td = tr.td(); td = tr.td();
pw = getProperty(obs, "note"); pw = getProperty(obs, "note");
if (valued(pw)) { if (valued(pw)) {
render(td, pw.value()); for (BaseWrapper b : pw.getValues()) {
render(td, b);
}
} }
} }
if (effectiveTime) { if (effectiveTime) {

View File

@ -73,7 +73,6 @@ import org.hl7.fhir.r5.renderers.utils.DirectWrappers.PropertyWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.DirectWrappers.ResourceWrapperDirect; import org.hl7.fhir.r5.renderers.utils.DirectWrappers.ResourceWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.ElementWrappers; import org.hl7.fhir.r5.renderers.utils.ElementWrappers;
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.ResourceWithReference; import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
@ -286,7 +285,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
// //
public void generateResourceSummary(XhtmlNode x, ResourceWrapper res, boolean textAlready, boolean showCodeDetails, boolean canLink) throws FHIRException, UnsupportedEncodingException, IOException { public void generateResourceSummary(XhtmlNode x, ResourceElement res, boolean textAlready, boolean showCodeDetails, boolean canLink) throws FHIRException, UnsupportedEncodingException, IOException {
if (!textAlready) { if (!textAlready) {
XhtmlNode div = res.getNarrative(); XhtmlNode div = res.getNarrative();
if (div != null) { if (div != null) {

View File

@ -37,6 +37,18 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
*/ */
public class Renderer { public class Renderer {
public static class RenderingStatus {
private boolean extensions;
public void setExtensions(boolean b) {
extensions = b;
}
public boolean getExtensions() {
return extensions;
}
}
protected RenderingContext context; protected RenderingContext context;
public Renderer(RenderingContext context) { public Renderer(RenderingContext context) {

View File

@ -4,7 +4,7 @@ import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
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.ResourceElement;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
public class RendererFactory { public class RendererFactory {
@ -62,14 +62,14 @@ public class RendererFactory {
} }
public static ResourceRenderer factory(ResourceWrapper resource, RenderingContext context, ResourceContext resourceContext) { public static ResourceRenderer factory(ResourceElement resource, RenderingContext context) {
if (context.getTemplateProvider() != null) { if (context.getTemplateProvider() != null) {
String liquidTemplate = context.getTemplateProvider().findTemplate(context, resource.getName()); String liquidTemplate = context.getTemplateProvider().findTemplate(context, resource.fhirType());
if (liquidTemplate != null) { if (liquidTemplate != null) {
return new LiquidRenderer(context, liquidTemplate); return new LiquidRenderer(context, liquidTemplate);
} }
} }
switch (resource.getName()) { switch (resource.fhirType()) {
case "DiagnosticReport": return new DiagnosticReportRenderer(context); case "DiagnosticReport": return new DiagnosticReportRenderer(context);
case "Library": return new LibraryRenderer(context); case "Library": return new LibraryRenderer(context);
case "List": return new ListRenderer(context); case "List": return new ListRenderer(context);
@ -77,11 +77,11 @@ public class RendererFactory {
case "QuestionnaireResponse": return new QuestionnaireResponseRenderer(context); case "QuestionnaireResponse": return new QuestionnaireResponseRenderer(context);
} }
return new ProfileDrivenRenderer(context, resourceContext); return new ProfileDrivenRenderer(context);
} }
public static ResourceRenderer factory(ResourceWrapper rw, RenderingContext lrc) { public static ResourceRenderer factory(ResourceWrapper rw, RenderingContext lrc) {
return factory(rw, lrc, null); return factory(rw, lrc);
} }
public static boolean hasSpecificRenderer(String rt) { public static boolean hasSpecificRenderer(String rt) {

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.r5.renderers; package org.hl7.fhir.r5.renderers;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.HashMap; import java.util.HashMap;
import java.util.ArrayList; import java.util.ArrayList;
@ -24,6 +25,7 @@ import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.Narrative; import org.hl7.fhir.r5.model.Narrative;
import org.hl7.fhir.r5.model.PrimitiveType; import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Property;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.Reference; import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
@ -34,9 +36,9 @@ import org.hl7.fhir.r5.renderers.utils.DirectWrappers.ResourceWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.ElementWrappers.ResourceWrapperMetaElement; import org.hl7.fhir.r5.renderers.utils.ElementWrappers.ResourceWrapperMetaElement;
import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceReferenceKind; import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceReferenceKind;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
import org.hl7.fhir.r5.renderers.utils.ResourceElement;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
@ -54,7 +56,6 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
protected ResourceContext rcontext;
protected XVerExtensionManager xverManager; protected XVerExtensionManager xverManager;
protected boolean multiLangMode; protected boolean multiLangMode;
@ -63,21 +64,6 @@ public abstract class ResourceRenderer extends DataRenderer {
super(context); super(context);
} }
public ResourceRenderer(RenderingContext context, ResourceContext rcontext) {
super(context);
this.rcontext = rcontext;
}
public ResourceContext getRcontext() {
return rcontext;
}
public ResourceRenderer setRcontext(ResourceContext rcontext) {
this.rcontext = rcontext;
return this;
}
public boolean isMultiLangMode() { public boolean isMultiLangMode() {
return multiLangMode; return multiLangMode;
} }
@ -87,13 +73,16 @@ public abstract class ResourceRenderer extends DataRenderer {
return this; return this;
} }
public XhtmlNode build(Resource dr) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome { public XhtmlNode build(ResourceElement dr) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
render(x, dr); renderResource(new RenderingStatus(), x, dr);
return x; return x;
} }
/** /**
* given a resource, update it's narrative with the best rendering available * given a resource, update it's narrative with the best rendering available.
*
* Explanation about native vs wrapped
* *
* @param r - the domain resource in question * @param r - the domain resource in question
* *
@ -101,39 +90,33 @@ public abstract class ResourceRenderer extends DataRenderer {
* @throws EOperationOutcome * @throws EOperationOutcome
* @throws FHIRException * @throws FHIRException
*/ */
public void renderResource(DomainResource r) throws IOException, FHIRException, EOperationOutcome {
public void render(DomainResource r) throws IOException, FHIRException, EOperationOutcome {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions; RenderingStatus status = new RenderingStatus();
hasExtensions = render(x, r); renderResource(status, x, r);
String an = r.fhirType()+"_"+r.getId(); String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) { if (context.isAddName()) {
if (!hasAnchorName(x, an)) { if (!hasAnchorName(x, an)) {
injectAnchorName(x, an); injectAnchorName(x, an);
} }
} }
inject(r, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED); inject(r, x, status.getExtensions() ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
} }
public XhtmlNode render(ResourceWrapper r) throws IOException, FHIRException, EOperationOutcome { public void renderResource(ResourceElement r) throws IOException, FHIRException, EOperationOutcome {
assert r.getContext() == context;
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, r); RenderingStatus status = new RenderingStatus();
renderResource(status, x, r);
String an = r.fhirType()+"_"+r.getId(); String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) { if (context.isAddName()) {
if (!hasAnchorName(x, an)) { if (!hasAnchorName(x, an)) {
injectAnchorName(x, an); injectAnchorName(x, an);
} }
} }
if (r.hasNarrative()) { inject(r, x, status.getExtensions() ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
r.injectNarrative(this, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
return x;
} }
public XhtmlNode checkNarrative(ResourceWrapper r) throws IOException, FHIRException, EOperationOutcome { public XhtmlNode checkNarrative(ResourceElement r) throws IOException, FHIRException, EOperationOutcome {
assert r.getContext() == context;
XhtmlNode x = r.getNarrative(); XhtmlNode x = r.getNarrative();
String an = r.fhirType()+"_"+r.getId(); String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) { if (context.isAddName()) {
@ -166,24 +149,35 @@ public abstract class ResourceRenderer extends DataRenderer {
return false; return false;
} }
public abstract boolean render(XhtmlNode x, Resource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome; // these three are what the descendants of this class override
public abstract void renderResource(RenderingStatus status, XhtmlNode x, ResourceElement r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome;
public void renderResource(RenderingStatus status, XhtmlNode x, DomainResource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
renderResource(status, x, new ResourceElement(context.getContextUtilities(), context.getProfileUtilities(), r));
}
public abstract String displayResource(ResourceElement r) throws UnsupportedEncodingException, IOException;
public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
ProfileDrivenRenderer pr = new ProfileDrivenRenderer(context); public String canonicalTitle(ResourceElement r) {
return pr.render(x, r); if (r.has("title")) {
return r.primitiveValue("title");
}
if (r.has("name")) {
return r.primitiveValue("name");
}
if (r.has("id")) {
return r.primitiveValue("id");
}
return "??";
} }
public void describe(XhtmlNode x, Resource r) throws UnsupportedEncodingException, IOException { public void describe(XhtmlNode x, ResourceElement r) throws UnsupportedEncodingException, IOException {
x.tx(display(r)); x.tx(displayDataType(r));
} }
public void describe(XhtmlNode x, ResourceWrapper r) throws UnsupportedEncodingException, IOException { public void inject(ResourceElement r, XhtmlNode x, NarrativeStatus status) {
x.tx(display(r)); r.setNarrative(x, status.toCode(), multiLangMode, context.getLocale());
} }
public abstract String display(Resource r) throws UnsupportedEncodingException, IOException;
public abstract String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException;
public void inject(DomainResource r, XhtmlNode x, NarrativeStatus status) { public void inject(DomainResource r, XhtmlNode x, NarrativeStatus status) {
r.getText().setUserData("renderer.generated", true); r.getText().setUserData("renderer.generated", true);
if (!r.hasText() || !r.getText().hasDiv()) { if (!r.hasText() || !r.getText().hasDiv()) {
@ -212,20 +206,23 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
} }
public void renderCanonical(Resource res, XhtmlNode x, String url) throws UnsupportedEncodingException, IOException { public void markLanguage(XhtmlNode x) {
ResourceWrapper rw = new ResourceWrapperDirect(this.context, res); x.setAttribute("lang", context.getLocale().toString());
renderCanonical(rw, x, url); x.setAttribute("xml:lang", context.getLocale().toString());
x.addTag(0, "hr");
x.addTag(0, "p").b().tx(context.getLocale().getDisplayName());
x.addTag(0, "hr");
} }
public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url) throws UnsupportedEncodingException, IOException { public void renderCanonical(ResourceElement res, XhtmlNode x, String url) throws UnsupportedEncodingException, IOException {
renderCanonical(rw, x, url, true, rw.getResource()); renderCanonical(res, x, url, true, res);
} }
public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url, boolean allowLinks, Resource src) throws UnsupportedEncodingException, IOException { public void renderCanonical(ResourceElement rw, XhtmlNode x, String url, boolean allowLinks, ResourceElement src) throws UnsupportedEncodingException, IOException {
if (url == null) { if (url == null) {
return; return;
} }
Resource target = context.getWorker().fetchResource(Resource.class, url, src); Resource target = context.getWorker().fetchResource(Resource.class, url, src.getResource());
if (target == null || !(target instanceof CanonicalResource)) { if (target == null || !(target instanceof CanonicalResource)) {
x.code().tx(url); x.code().tx(url);
} else { } else {
@ -249,56 +246,65 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
} }
public void render(Resource res, XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException { public void renderReference(RenderingStatus status, ResourceElement res, XhtmlNode x, ResourceElement type) throws FHIRFormatError, DefinitionException, IOException {
if (type instanceof Reference) { if (type.fhirType().equals("Reference")) {
renderReference(res, x, (Reference) type); renderReference(status, res, x, type);
} else if (type instanceof CodeableReference) { } else if (type.fhirType().equals("CodeableReference")) {
CodeableReference cr = (CodeableReference) type; if (type.has("reference")) {
if (cr.hasReference()) { renderReference(status, res, x, type, true);
renderReference(res, x, cr.getReference());
} else { } else {
render(x, type); renderDataType(status, x, type);
} }
} else { } else {
render(x, type); renderDataType(status, x, type);
} }
} }
public void render(ResourceWrapper res, XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException { /*
if (type instanceof Reference) { * } else if (ew.fhirType().equals("Reference")) {
renderReference(res, x, (Reference) type); Reference r = (Reference) e;
} else if (type instanceof CodeableReference) { if (r.getReference() != null && r.getReference().contains("#")) {
CodeableReference cr = (CodeableReference) type; if (containedIds.contains(r.getReference().substring(1))) {
if (cr.hasReference()) { x.ah("#hc"+r.getReference().substring(1)).tx("See "+r.getReference());
renderReference(res, x, cr.getReference());
} else { } else {
render(x, type); // 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 {
String ref = context.getResolver() != null ?context.getResolver().urlForContained(context, res.fhirType(), res.getId(), rw.fhirType(), rw.getId()) : null;
if (ref == null) {
x.an("hc"+rw.getId());
RenderingContext ctxtc = context.copy();
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());
}
}
} }
} else { } else {
render(x, type); renderReference(res, x, r);
} }
} */
public void renderReference(Resource res, XhtmlNode x, Reference r) throws UnsupportedEncodingException, IOException {
ResourceWrapper rw = new ResourceWrapperDirect(this.context, res);
renderReference(rw, x, r);
}
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r) throws UnsupportedEncodingException, IOException {
renderReference(rw, x, r, true);
}
public void renderReference(Resource res, HierarchicalTableGenerator gen, List<Piece> pieces, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException { public void renderReference(Resource res, HierarchicalTableGenerator gen, List<Piece> pieces, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException {
if (r == null) { if (r == null) {
pieces.add(gen.new Piece(null, "null!", null)); pieces.add(gen.new Piece(null, "null!", null));
return; return;
} }
ResourceWrapper rw = new ResourceWrapperDirect(this.context, res);
ResourceWithReference tr = null; ResourceWithReference tr = null;
String link = null; String link = null;
StringBuilder text = new StringBuilder(); StringBuilder text = new StringBuilder();
if (r.hasReferenceElement() && allowLinks) { if (r.hasReferenceElement() && allowLinks) {
tr = resolveReference(rw, r.getReference()); tr = resolveReference(new ResourceElement(context.getContextUtilities(), context.getProfileUtilities(), res), r.getReference());
if (!r.getReference().startsWith("#")) { if (!r.getReference().startsWith("#")) {
if (tr != null && tr.getReference() != null) { if (tr != null && tr.getReference() != null) {
@ -315,13 +321,13 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
// what to display: if text is provided, then that. if the reference was resolved, then show the name, or the generated narrative // what to display: if text is provided, then that. if the reference was resolved, then show the name, or the generated narrative
String display = r.hasDisplayElement() ? r.getDisplay() : null; String display = r.hasDisplayElement() ? r.getDisplay() : null;
String name = tr != null && tr.getResource() != null ? tr.getResource().getNameFromResource() : null; String name = tr != null && tr.getResource() != null ? getNameForResource(tr.getResource()) : null;
if (display == null && (tr == null || tr.getResource() == null)) { if (display == null && (tr == null || tr.getResource() == null)) {
if (!Utilities.noString(r.getReference())) { if (!Utilities.noString(r.getReference())) {
text.append(r.getReference()); text.append(r.getReference());
} else if (r.hasIdentifier()) { } else if (r.hasIdentifier()) {
text.append(displayIdentifier(r.getIdentifier())); text.append(displayIdentifier(new ResourceElement(context.getContextUtilities(), context.getProfileUtilities(), r.getIdentifier())));
} else { } else {
text.append("??"); text.append("??");
} }
@ -364,7 +370,31 @@ public abstract class ResourceRenderer extends DataRenderer {
pieces.add(gen.new Piece(link,text.toString(), null)); pieces.add(gen.new Piece(link,text.toString(), null));
} }
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException { private String getNameForResource(ResourceElement resource) {
ResourceElement name = resource.firstChild("name");
if (name != null && !name.isEmpty()) {
if (name.isPrimitive()) {
return name.primitiveValue();
} else if (name.fhirType().equals("HumanName")) {
String family = name.primitiveValue("family");
String given = name.firstPrimitiveValue("given");
return (family == null) ? given : given == null ? family : family+" "+given;
} else {
String n = name.primitiveValueMN("name", "text", "value");
if (n != null) {
return n;
}
}
}
String n = resource.primitiveValue("productName");
if (n == null) {
throw new Error("What to render for 'name'? Type is "+resource.fhirType());
} else {
return n;
}
}
public void renderReference(RenderingStatus status, ResourceElement rw, XhtmlNode x, ResourceElement r, boolean allowLinks) throws UnsupportedEncodingException, IOException {
if (r == null) { if (r == null) {
x.tx("null!"); x.tx("null!");
return; return;
@ -372,10 +402,11 @@ public abstract class ResourceRenderer extends DataRenderer {
XhtmlNode c = null; XhtmlNode c = null;
ResourceWithReference tr = null; ResourceWithReference tr = null;
boolean onPage = false; boolean onPage = false;
if (r.hasReferenceElement() && allowLinks) { String rref = r.primitiveValue("reference");
tr = resolveReference(rw, r.getReference()); if (r.has("reference") && allowLinks) {
tr = resolveReference(rw, r.primitiveValue("reference"));
if (!r.getReference().startsWith("#")) { if (!rref.startsWith("#")) {
if (tr != null && tr.getReference() != null) { if (tr != null && tr.getReference() != null) {
if (tr.getReference().startsWith("#")) { if (tr.getReference().startsWith("#")) {
onPage = true; onPage = true;
@ -387,16 +418,16 @@ public abstract class ResourceRenderer extends DataRenderer {
} else { } else {
c = x.ah(tr.getReference()); c = x.ah(tr.getReference());
} }
} else if (r.getReference().contains("?")) { } else if (rref.contains("?")) {
x.tx(context.formatPhrase(RenderingContext.RES_REND_COND_REF)+" "); x.tx(context.formatPhrase(RenderingContext.RES_REND_COND_REF)+" ");
c = x.code(""); c = x.code("");
} else { } else {
c = x.ah(r.getReference()); c = x.ah(rref);
} }
} else if ("#".equals(r.getReference())) { } else if ("#".equals(rref)) {
c = x.ah("#"); c = x.ah("#");
} else if (context.getRules() == GenerationRules.IG_PUBLISHER || (tr != null && tr.getKind() != ResourceReferenceKind.BUNDLE)) { } else if (context.getRules() == GenerationRules.IG_PUBLISHER || (tr != null && tr.getKind() != ResourceReferenceKind.BUNDLE)) {
c = x.ah("#hc"+r.getReference().substring(1)); c = x.ah("#hc"+rref.substring(1));
onPage = true; onPage = true;
} else { } else {
c = x; c = x;
@ -408,19 +439,19 @@ public abstract class ResourceRenderer extends DataRenderer {
c.tx(context.formatPhrase(RenderingContext.RES_REND_SEE_ON_THIS_PAGE)+" "); c.tx(context.formatPhrase(RenderingContext.RES_REND_SEE_ON_THIS_PAGE)+" ");
} }
// what to display: if text is provided, then that. if the reference was resolved, then show the name, or the generated narrative // what to display: if text is provided, then that. if the reference was resolved, then show the name, or the generated narrative
String display = r.hasDisplayElement() ? r.getDisplay() : null; String display = r.has("display") ? r.primitiveValue("display") : null;
String name = tr != null && tr.getResource() != null ? tr.getResource().getNameFromResource() : null; String name = tr != null && tr.getResource() != null ? getNameForResource(tr.getResource()) : null;
if (display == null && (tr == null || tr.getResource() == null)) { if (display == null && (tr == null || tr.getResource() == null)) {
if (!Utilities.noString(r.getReference())) { if (!Utilities.noString(rref)) {
c.addText(r.getReference()); c.addText(rref);
} else if (r.hasIdentifier()) { } else if (r.has("identifier")) {
renderIdentifier(c, r.getIdentifier()); renderIdentifier(status, c, r.child("identifier"));
} else { } else {
c.addText("??"); c.addText("??");
} }
} else if (context.isTechnicalMode()) { } else if (context.isTechnicalMode()) {
c.addText(r.getReference()); c.addText(rref);
if (display != null) { if (display != null) {
c.addText(": "+display); c.addText(": "+display);
} }
@ -429,16 +460,16 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
if (r.hasExtension(ToolingExtensions.EXT_TARGET_ID) || r.hasExtension(ToolingExtensions.EXT_TARGET_PATH)) { if (r.hasExtension(ToolingExtensions.EXT_TARGET_ID) || r.hasExtension(ToolingExtensions.EXT_TARGET_PATH)) {
x.addText("("); x.addText("(");
for (Extension ex : r.getExtensionsByUrl(ToolingExtensions.EXT_TARGET_ID)) { for (ResourceElement ex : r.extensions(ToolingExtensions.EXT_TARGET_ID)) {
if (ex.hasValue()) { if (ex.has("value")) {
x.sep(", "); x.sep(", ");
x.addText("#"+ex.getValue().primitiveValue()); x.addText("#"+ex.primitiveValue("value"));
} }
} }
for (Extension ex : r.getExtensionsByUrl(ToolingExtensions.EXT_TARGET_PATH)) { for (ResourceElement ex : r.extensions(ToolingExtensions.EXT_TARGET_PATH)) {
if (ex.hasValue()) { if (ex.has("value")) {
x.sep(", "); x.sep(", ");
x.addText("/#"+ex.getValue().primitiveValue()); x.addText("/#"+ex.primitiveValue("value"));
} }
} }
x.addText(")"); x.addText(")");
@ -451,48 +482,48 @@ public abstract class ResourceRenderer extends DataRenderer {
} else { } else {
c.tx(context.formatPhrase(RenderingContext.RES_REND_GEN_SUM)+" "); c.tx(context.formatPhrase(RenderingContext.RES_REND_GEN_SUM)+" ");
if (tr != null) { if (tr != null) {
new ProfileDrivenRenderer(context).generateResourceSummary(c, tr.getResource(), true, r.getReference().startsWith("#"), true); new ProfileDrivenRenderer(context).generateResourceSummary(c, tr.getResource(), true, rref.startsWith("#"), true);
} }
} }
} }
} }
//
// public void renderReference(ResourceWrapper rw, XhtmlNode x, BaseWrapper r) throws UnsupportedEncodingException, IOException {
// XhtmlNode c = x;
// ResourceWithReference tr = null;
// String v;
// if (r.has("reference")) {
// v = r.get("reference").primitiveValue();
// tr = resolveReference(rw, v);
//
// if (!v.startsWith("#")) {
// if (tr != null && tr.getReference() != null)
// c = x.ah(tr.getReference());
// else
// c = x.ah(v);
// }
// } else {
// v = "";
// }
// // what to display: if text is provided, then that. if the reference was resolved, then show the generated narrative
// if (r.has("display")) {
// c.addText(r.get("display").primitiveValue());
// if (tr != null && tr.getResource() != null) {
// c.tx(context.formatPhrase(RenderingContext.RES_REND_GEN_SUM)+" ");
// new ProfileDrivenRenderer(context).generateResourceSummary(c, tr.getResource(), true, v.startsWith("#"), false);
// }
// } else if (tr != null && tr.getResource() != null) {
// new ProfileDrivenRenderer(context).generateResourceSummary(c, tr.getResource(), v.startsWith("#"), v.startsWith("#"), false);
// } else {
// c.addText(v);
// }
// }
public void renderReference(ResourceWrapper rw, XhtmlNode x, BaseWrapper r) throws UnsupportedEncodingException, IOException { protected ResourceWithReference resolveReference(ResourceElement res, String url) {
XhtmlNode c = x;
ResourceWithReference tr = null;
String v;
if (r.has("reference")) {
v = r.get("reference").primitiveValue();
tr = resolveReference(rw, v);
if (!v.startsWith("#")) {
if (tr != null && tr.getReference() != null)
c = x.ah(tr.getReference());
else
c = x.ah(v);
}
} else {
v = "";
}
// what to display: if text is provided, then that. if the reference was resolved, then show the generated narrative
if (r.has("display")) {
c.addText(r.get("display").primitiveValue());
if (tr != null && tr.getResource() != null) {
c.tx(context.formatPhrase(RenderingContext.RES_REND_GEN_SUM)+" ");
new ProfileDrivenRenderer(context).generateResourceSummary(c, tr.getResource(), true, v.startsWith("#"), false);
}
} else if (tr != null && tr.getResource() != null) {
new ProfileDrivenRenderer(context).generateResourceSummary(c, tr.getResource(), v.startsWith("#"), v.startsWith("#"), false);
} else {
c.addText(v);
}
}
protected ResourceWithReference resolveReference(ResourceWrapper res, String url) {
if (url == null) if (url == null)
return null; return null;
if (url.startsWith("#") && res != null) { if (url.startsWith("#") && res != null) {
for (ResourceWrapper r : res.getContained()) { for (ResourceElement r : res.children("contained")) {
if (r.getId().equals(url.substring(1))) if (r.getId().equals(url.substring(1)))
return new ResourceWithReference(ResourceReferenceKind.CONTAINED, url, r); return new ResourceWithReference(ResourceReferenceKind.CONTAINED, url, r);
} }
@ -503,7 +534,7 @@ public abstract class ResourceRenderer extends DataRenderer {
version = url.substring(url.indexOf("/_history/")+10); version = url.substring(url.indexOf("/_history/")+10);
url = url.substring(0, url.indexOf("/_history/")); url = url.substring(0, url.indexOf("/_history/"));
} }
/*
if (rcontext != null) { if (rcontext != null) {
BundleEntryComponent bundleResource = rcontext.resolve(url); BundleEntryComponent bundleResource = rcontext.resolve(url);
if (bundleResource != null) { if (bundleResource != null) {
@ -512,7 +543,7 @@ public abstract class ResourceRenderer extends DataRenderer {
id = makeIdFromBundleEntry(bundleResource.getFullUrl()); id = makeIdFromBundleEntry(bundleResource.getFullUrl());
} }
String bundleUrl = "#" + bundleResource.getResource().getResourceType().name() + "_" + id; String bundleUrl = "#" + bundleResource.getResource().getResourceType().name() + "_" + id;
return new ResourceWithReference(ResourceReferenceKind.BUNDLE, bundleUrl, new ResourceWrapperDirect(this.context, bundleResource.getResource())); return new ResourceWithReference(ResourceReferenceKind.BUNDLE, bundleUrl, new ResourceElement(this.context.getContextUtilities(), bundleResource.getResource()));
} }
org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version); org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version);
if (bundleElement != null) { if (bundleElement != null) {
@ -527,13 +558,13 @@ public abstract class ResourceRenderer extends DataRenderer {
} else { } else {
bundleUrl = "#" +fullUrlToAnchor(bundleElement.getChildValue("fullUrl")); bundleUrl = "#" +fullUrlToAnchor(bundleElement.getChildValue("fullUrl"));
} }
return new ResourceWithReference(ResourceReferenceKind.BUNDLE, bundleUrl, new ResourceWrapperMetaElement(this.context, br)); return new ResourceWithReference(ResourceReferenceKind.BUNDLE, bundleUrl, new ResourceElement(this.context.getContextUtilities(), br));
} }
} }
*/
Resource ae = getContext().getWorker().fetchResource(null, url, version); Resource ae = getContext().getWorker().fetchResource(null, url, version);
if (ae != null) if (ae != null)
return new ResourceWithReference(ResourceReferenceKind.EXTERNAL, url, new ResourceWrapperDirect(this.context, ae)); return new ResourceWithReference(ResourceReferenceKind.EXTERNAL, url, new ResourceElement(this.context.getContextUtilities(), this.context.getProfileUtilities(), ae));
else if (context.getResolver() != null) { else if (context.getResolver() != null) {
return context.getResolver().resolve(context, url); return context.getResolver().resolve(context, url);
} else } else
@ -570,14 +601,6 @@ public abstract class ResourceRenderer extends DataRenderer {
return null; return null;
} }
protected PropertyWrapper getProperty(ResourceWrapper res, String name) {
for (PropertyWrapper t : res.children()) {
if (t.getName().equals(name))
return t;
}
return null;
}
protected PropertyWrapper getProperty(BaseWrapper res, String name) { protected PropertyWrapper getProperty(BaseWrapper res, String name) {
for (PropertyWrapper t : res.children()) { for (PropertyWrapper t : res.children()) {
if (t.getName().equals(name)) if (t.getName().equals(name))
@ -591,18 +614,18 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
protected ResourceWrapper fetchResource(BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException { // protected ResourceElement fetchResource(BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException {
if (context.getResolver() == null) // if (context.getResolver() == null)
return null; // return null;
//
PropertyWrapper ref = subject.getChildByName("reference"); // PropertyWrapper ref = subject.getChildByName("reference");
if (ref == null || !ref.hasValues()) { // if (ref == null || !ref.hasValues()) {
return null; // return null;
} // }
String url = ref.value().getBase().primitiveValue(); // String url = ref.value().getBase().primitiveValue();
ResourceWithReference rr = context.getResolver().resolve(context, url); // ResourceWithReference rr = context.getResolver().resolve(context, url);
return rr == null ? null : rr.getResource(); // return rr == null ? null : rr.getResource();
} // }
protected String describeStatus(PublicationStatus status, boolean experimental) { protected String describeStatus(PublicationStatus status, boolean experimental) {
@ -637,22 +660,23 @@ public abstract class ResourceRenderer extends DataRenderer {
return true; return true;
} }
protected void renderResourceHeader(ResourceWrapper r, XhtmlNode x, boolean doId) throws UnsupportedEncodingException, FHIRException, IOException { protected void renderResourceHeader(ResourceElement r, XhtmlNode x, boolean doId) throws UnsupportedEncodingException, FHIRException, IOException {
XhtmlNode div = x.div().style("display: inline-block").style("background-color: #d9e0e7").style("padding: 6px") XhtmlNode div = x.div().style("display: inline-block").style("background-color: #d9e0e7").style("padding: 6px")
.style("margin: 4px").style("border: 1px solid #8da1b4") .style("margin: 4px").style("border: 1px solid #8da1b4")
.style("border-radius: 5px").style("line-height: 60%"); .style("border-radius: 5px").style("line-height: 60%");
String id = getPrimitiveValue(r, "id"); RenderingStatus status = new RenderingStatus();
String id = r.primitiveValue("id");
if (doId) { if (doId) {
div.an("hc"+id); div.an("hc"+id);
} }
String lang = getPrimitiveValue(r, "language"); String lang = r.primitiveValue("language");
String ir = getPrimitiveValue(r, "implicitRules"); String ir = r.primitiveValue("implicitRules");
BaseWrapper meta = r.getChildByName("meta").hasValues() ? r.getChildByName("meta").getValues().get(0) : null; ResourceElement meta = r.has("meta") && r.child("meta").isEmpty() ? r.child("meta") : null;
String versionId = getPrimitiveValue(meta, "versionId"); ResourceElement versionId = meta == null ? null : meta.child("versionId");
String lastUpdated = getPrimitiveValue(meta, "lastUpdated"); ResourceElement lastUpdated = meta == null ? null : meta.child("lastUpdated");
String source = getPrimitiveValue(meta, "source"); ResourceElement source = meta == null ? null : meta.child("source");
if (id != null || lang != null || versionId != null || lastUpdated != null) { if (id != null || lang != null || versionId != null || lastUpdated != null) {
XhtmlNode p = plateStyle(div.para()); XhtmlNode p = plateStyle(div.para());
@ -667,7 +691,7 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
if (lastUpdated != null) { if (lastUpdated != null) {
p.tx(context.formatPhrase(RenderingContext.RES_REND_UPDATED) + "\""); p.tx(context.formatPhrase(RenderingContext.RES_REND_UPDATED) + "\"");
renderDateTime(p, lastUpdated); renderDataType(status, p, lastUpdated);
p.tx("\" "); p.tx("\" ");
} }
if (lang != null) { if (lang != null) {
@ -681,42 +705,34 @@ public abstract class ResourceRenderer extends DataRenderer {
plateStyle(div.para()).tx(context.formatPhrase(RenderingContext.RES_REND_INFO_SOURCE) + " "+source+"!"); plateStyle(div.para()).tx(context.formatPhrase(RenderingContext.RES_REND_INFO_SOURCE) + " "+source+"!");
} }
if (meta != null) { if (meta != null) {
PropertyWrapper pl = meta.getChildByName("profile"); List<ResourceElement> items = meta.children("profile");
if (pl.hasValues()) { if (!items.isEmpty()) {
XhtmlNode p = plateStyle(div.para()); XhtmlNode p = plateStyle(div.para());
p.tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_PROF), pl.getValues().size())+": "); p.tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_PROF), items.size())+": ");
boolean first = true; boolean first = true;
for (BaseWrapper bw : pl.getValues()) { for (ResourceElement bw : items) {
if (first) first = false; else p.tx(", "); if (first) first = false; else p.tx(", ");
renderCanonical(r, p, bw.getBase().primitiveValue()); renderCanonical(r, p, bw.primitiveValue());
} }
} }
PropertyWrapper tl = meta.getChildByName("tag"); items = meta.children("tag");
if (tl.hasValues()) { if (!items.isEmpty()) {
XhtmlNode p = plateStyle(div.para()); XhtmlNode p = plateStyle(div.para());
p.tx(Utilities.pluralize(context.formatPhrase(RenderingContext.RES_REND_TAG), tl.getValues().size())+": "); p.tx(Utilities.pluralize(context.formatPhrase(RenderingContext.RES_REND_TAG), items.size())+": ");
boolean first = true; boolean first = true;
for (BaseWrapper bw : tl.getValues()) { for (ResourceElement bw : items) {
if (first) first = false; else p.tx(", "); if (first) first = false; else p.tx(", ");
String system = getPrimitiveValue(bw, "system"); renderCoding(status, p, bw);
String version = getPrimitiveValue(bw, "version");
String code = getPrimitiveValue(bw, "system");
String display = getPrimitiveValue(bw, "system");
renderCoding(p, new Coding(system, version, code, display));
} }
} }
PropertyWrapper sl = meta.getChildByName("security"); items = meta.children("security");
if (sl.hasValues()) { if (!items.isEmpty()) {
XhtmlNode p = plateStyle(div.para()); XhtmlNode p = plateStyle(div.para());
p.tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_SECURITY_LABEL), tl.getValues().size())+": "); p.tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_SECURITY_LABEL), items.size())+": ");
boolean first = true; boolean first = true;
for (BaseWrapper bw : sl.getValues()) { for (ResourceElement bw : items) {
if (first) first = false; else p.tx(", "); if (first) first = false; else p.tx(", ");
String system = getPrimitiveValue(bw, "system"); renderCoding(status, p, bw);
String version = getPrimitiveValue(bw, "version");
String code = getPrimitiveValue(bw, "system");
String display = getPrimitiveValue(bw, "system");
renderCoding(p, new Coding(system, version, code, display));
} }
} }
} }
@ -735,27 +751,27 @@ public abstract class ResourceRenderer extends DataRenderer {
return r.has(name) && r.getChildByName(name).hasValues() ? r.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null; return r.has(name) && r.getChildByName(name).hasValues() ? r.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null;
} }
public void renderOrError(DomainResource dr) { // public void renderOrError(DomainResource dr) {
try { // try {
render(dr); // render(dr);
} catch (Exception e) { // } catch (Exception e) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); // XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.para().tx(context.formatPhrase(RenderingContext.RES_REND_ERROR, e.getMessage())+" "); // x.para().tx(context.formatPhrase(RenderingContext.RES_REND_ERROR, e.getMessage())+" ");
dr.setText(null); // dr.setText(null);
inject(dr, x, NarrativeStatus.GENERATED); // inject(dr, x, NarrativeStatus.GENERATED);
} // }
//
} // }
public RendererType getRendererType() { public RendererType getRendererType() {
return RendererType.NATIVE; return RendererType.NATIVE;
} }
public class TableRowData { public class TableRowData {
private Map<String, List<DataType>> cols = new HashMap<>(); private Map<String, List<ResourceElement>> cols = new HashMap<>();
private TableData data; private TableData data;
public void value(String name, DataType value) { public void value(String name, ResourceElement value) {
if (!cols.containsKey(name)) { if (!cols.containsKey(name)) {
cols.put(name, new ArrayList<>()); cols.put(name, new ArrayList<>());
} }
@ -769,7 +785,7 @@ public abstract class ResourceRenderer extends DataRenderer {
return cols.containsKey(name); return cols.containsKey(name);
} }
public List<DataType> get(String name) { public List<ResourceElement> get(String name) {
return cols.get(name); return cols.get(name);
} }
@ -802,7 +818,7 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
public void renderTable(TableData provider, XhtmlNode x) throws FHIRFormatError, DefinitionException, IOException { public void renderTable(RenderingStatus status, TableData provider, XhtmlNode x) throws FHIRFormatError, DefinitionException, IOException {
List<String> columns = new ArrayList<>(); List<String> columns = new ArrayList<>();
for (String name : provider.getColumns()) { for (String name : provider.getColumns()) {
boolean hasData = false; boolean hasData = false;
@ -830,11 +846,11 @@ public abstract class ResourceRenderer extends DataRenderer {
for (String col : columns) { for (String col : columns) {
XhtmlNode td = tr.td(); XhtmlNode td = tr.td();
boolean first = true; boolean first = true;
List<DataType> list = row.get(col); List<ResourceElement> list = row.get(col);
if (list != null) { if (list != null) {
for (DataType value : list) { for (ResourceElement value : list) {
if (first) first = false; else td.tx(", "); if (first) first = false; else td.tx(", ");
render(td, value); renderDataType(status, td, value);
} }
} }
} }
@ -842,13 +858,4 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
} }
public void markLanguage(XhtmlNode x) {
x.setAttribute("lang", context.getLocale().toString());
x.setAttribute("xml:lang", context.getLocale().toString());
x.addTag(0, "hr");
x.addTag(0, "p").b().tx(context.getLocale().getDisplayName());
x.addTag(0, "hr");
}
} }

View File

@ -35,6 +35,7 @@ import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DecimalType; import org.hl7.fhir.r5.model.DecimalType;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Element; import org.hl7.fhir.r5.model.Element;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.AdditionalBindingPurposeVS; import org.hl7.fhir.r5.model.ElementDefinition.AdditionalBindingPurposeVS;
@ -71,12 +72,14 @@ import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.InternalMarkdownPro
import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.RenderStyle; import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.RenderStyle;
import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.SourcedElementDefinition; import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.SourcedElementDefinition;
import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.ResourceElement;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.FixedValueFormat; import org.hl7.fhir.r5.renderers.utils.RenderingContext.FixedValueFormat;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.StructureDefinitionRendererMode; import org.hl7.fhir.r5.renderers.utils.RenderingContext.StructureDefinitionRendererMode;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; import org.hl7.fhir.r5.renderers2.Renderer.RenderingStatus;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.PublicationHacker; import org.hl7.fhir.r5.utils.PublicationHacker;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
@ -101,6 +104,27 @@ import org.hl7.fhir.utilities.xhtml.XhtmlParser;
public class StructureDefinitionRenderer extends ResourceRenderer { public class StructureDefinitionRenderer extends ResourceRenderer {
public StructureDefinitionRenderer(RenderingContext context) {
super(context);
hostMd = new InternalMarkdownProcessor();
corePath = context.getContext().getSpecUrl();
}
@Override
public void renderResource(RenderingStatus status, XhtmlNode x, ResourceElement r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
throw new Error("StructureDefinitionRenderer only renders native resources directly");
}
@Override
public void renderResource(RenderingStatus status, XhtmlNode x, DomainResource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
render(status, x, (StructureDefinition) r);
}
@Override
public String displayResource(ResourceElement r) throws UnsupportedEncodingException, IOException {
return canonicalTitle(r);
}
public enum RenderStyle { public enum RenderStyle {
} }
@ -302,16 +326,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
private Map<String, Map<String, ElementDefinition>> sdMapCache = new HashMap<>(); private Map<String, Map<String, ElementDefinition>> sdMapCache = new HashMap<>();
private IMarkdownProcessor hostMd; private IMarkdownProcessor hostMd;
public StructureDefinitionRenderer(RenderingContext context) {
super(context);
hostMd = new InternalMarkdownProcessor();
corePath = context.getContext().getSpecUrl();
}
public StructureDefinitionRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext);
}
public Map<String, Map<String, ElementDefinition>> getSdMapCache() { public Map<String, Map<String, ElementDefinition>> getSdMapCache() {
return sdMapCache; return sdMapCache;
@ -329,18 +343,15 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
this.hostMd = hostMd; this.hostMd = hostMd;
} }
public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException {
return render(x, (StructureDefinition) dr);
}
public boolean render(XhtmlNode x, StructureDefinition sd) throws FHIRFormatError, DefinitionException, IOException { public void render(RenderingStatus status, XhtmlNode x, StructureDefinition sd) throws FHIRFormatError, DefinitionException, IOException {
if (context.getStructureMode() == StructureDefinitionRendererMode.DATA_DICT) { if (context.getStructureMode() == StructureDefinitionRendererMode.DATA_DICT) {
renderDict(sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, ""); renderDict(sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, "");
} else { } else {
x.getChildNodes().add(generateTable(context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, x.getChildNodes().add(generateTable(context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false,
context.getLink(KnownLinkType.SPEC), "", sd.getKind() == StructureDefinitionKind.LOGICAL, false, null, false, context, "")); context.getLink(KnownLinkType.SPEC), "", sd.getKind() == StructureDefinitionKind.LOGICAL, false, null, false, context, ""));
} }
return true; status.setExtensions(true);
} }
public void describe(XhtmlNode x, StructureDefinition sd) { public void describe(XhtmlNode x, StructureDefinition sd) {
@ -351,10 +362,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return sd.present(); return sd.present();
} }
@Override
public String display(Resource r) throws UnsupportedEncodingException, IOException {
return ((StructureDefinition) r).present();
}
public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
if (r.has("title")) { if (r.has("title")) {

View File

@ -28,6 +28,7 @@ public class Resolver {
String resolveUri(RenderingContext context, String uri); String resolveUri(RenderingContext context, String uri);
} }
/*
public static class ResourceContext { public static class ResourceContext {
private ResourceContext container; private ResourceContext container;
@ -183,7 +184,7 @@ public class Resolver {
} }
} }
} }
*/
public enum ResourceReferenceKind { public enum ResourceReferenceKind {
CONTAINED, BUNDLE, EXTERNAL, UNKNOWN CONTAINED, BUNDLE, EXTERNAL, UNKNOWN
@ -194,9 +195,9 @@ public class Resolver {
private ResourceReferenceKind kind; private ResourceReferenceKind kind;
private String reference; private String reference;
private ResourceWrapper resource; private ResourceElement resource;
public ResourceWithReference(ResourceReferenceKind kind, String reference, ResourceWrapper resource) { public ResourceWithReference(ResourceReferenceKind kind, String reference, ResourceElement resource) {
super(); super();
this.kind = kind; this.kind = kind;
this.reference = reference; this.reference = reference;
@ -211,7 +212,7 @@ public class Resolver {
return reference; return reference;
} }
public ResourceWrapper getResource() { public ResourceElement getResource() {
return resource; return resource;
} }
} }

View File

@ -6,16 +6,18 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions;
import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Narrative; import org.hl7.fhir.r5.model.Narrative;
import org.hl7.fhir.r5.model.Property; import org.hl7.fhir.r5.model.Property;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.client.network.FhirRequestBuilder;
import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlNode;
@ -35,46 +37,77 @@ public class ResourceElement {
IndependentResource IndependentResource
} }
private ContextUtilities context; public static class NamedResourceElementList {
private String name;
private List<ResourceElement> values = new ArrayList<ResourceElement>();
public NamedResourceElementList(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public List<ResourceElement> getValues() {
return values;
}
}
private ContextUtilities contextUtils;
private ProfileUtilities profileUtils;
private ResourceElement parent; private ResourceElement parent;
private String name; // null at root private String name; // null at root
private int index; // -1 if not repeating private int index; // -1 if not repeating
private ElementKind kind; private ElementKind kind;
private StructureDefinition classDefinition;
private ElementDefinition propertyDefinition;
private Base element; private Base element;
private Element model; private Element model;
private List<ResourceElement> children; private List<ResourceElement> children;
public ResourceElement(ContextUtilities context, Resource resource) { public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, Resource resource) {
this.context = context; this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = null; this.parent = null;
this.name = null; this.name = null;
this.index = -1; this.index = -1;
this.kind = ElementKind.IndependentResource; this.kind = ElementKind.IndependentResource;
this.element = resource; this.element = resource;
this.classDefinition = profileUtils.getContext().fetchTypeDefinition(resource.fhirType());
this.propertyDefinition = this.classDefinition.getSnapshot().getElementFirstRep();
} }
public ResourceElement(ContextUtilities context, DataType type) { public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, DataType type) {
this.context = context; this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = null; this.parent = null;
this.name = null; this.name = null;
this.index = -1; this.index = -1;
this.kind = null; this.kind = null;
this.element = type; this.element = type;
this.classDefinition = profileUtils.getContext().fetchTypeDefinition(type.fhirType());
this.propertyDefinition = this.classDefinition.getSnapshot().getElementFirstRep();
} }
public ResourceElement(ContextUtilities context, ResourceElement parent, String name, int index, ElementKind kind, Base element) { public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, ResourceElement parent, String name, int index, ElementKind kind, Base element, StructureDefinition classDefinition, ElementDefinition propertyDefinition) {
this.context = context; this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = parent; this.parent = parent;
this.name = name; this.name = name;
this.index = index; this.index = index;
this.kind = kind; this.kind = kind;
this.element = element; this.element = element;
this.classDefinition = classDefinition;
this.propertyDefinition = propertyDefinition;
} }
public ResourceElement(ContextUtilities context, Element resource) { public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, Element resource) {
this.context = context; this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = null; this.parent = null;
this.name = null; this.name = null;
this.index = -1; this.index = -1;
@ -82,13 +115,16 @@ public class ResourceElement {
this.model = resource; this.model = resource;
} }
public ResourceElement(ContextUtilities context, ResourceElement parent, String name, int index, ElementKind kind, Element em) { public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, ResourceElement parent, String name, int index, ElementKind kind, Element em) {
this.context = context; this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = parent; this.parent = parent;
this.name = name; this.name = name;
this.index = index; this.index = index;
this.kind = kind; this.kind = kind;
this.model = em; this.model = em;
this.classDefinition = em.getProperty().getStructure();
this.propertyDefinition = em.getProperty().getDefinition();
} }
public String fhirVersion() { public String fhirVersion() {
@ -201,7 +237,7 @@ public class ResourceElement {
String name = child.getProperty().isChoice() ? child.getProperty().getName() : child.getName(); String name = child.getProperty().isChoice() ? child.getProperty().getName() : child.getName();
int index = child.isList() ? child.getIndex() : -1; int index = child.isList() ? child.getIndex() : -1;
ElementKind kind = determineModelKind(child); ElementKind kind = determineModelKind(child);
children.add(new ResourceElement(context, this, name, index, kind, child)); children.add(new ResourceElement(contextUtils, profileUtils, this, name, index, kind, child));
} }
} }
@ -233,13 +269,29 @@ public class ResourceElement {
} }
private void loadElementChildren() { private void loadElementChildren() {
SourcedChildDefinitions childDefs = propertyDefinition == null ? null : profileUtils.getChildMap(classDefinition, propertyDefinition);
for (Property p : element.children()) { for (Property p : element.children()) {
String name = p.getName(); String name = p.getName();
int i = 0; int i = 0;
for (Base v : p.getValues()) { for (Base v : p.getValues()) {
ElementKind kind = determineModelKind(p, v); ElementKind kind = determineModelKind(p, v);
int index = p.isList() ? i : -1; int index = p.isList() ? i : -1;
children.add(new ResourceElement(context, this, name, index, kind, v)); ElementDefinition ed = null;
if (childDefs != null) {
for (ElementDefinition t : childDefs.getList()) {
if (t.getName().equals(name)) {
ed = t;
break;
}
}
}
if (ed != null) {
children.add(new ResourceElement(contextUtils, profileUtils, this, name, index, kind, v, childDefs.getSource(), ed));
} else {
StructureDefinition sd = profileUtils.getContext().fetchTypeDefinition(v.fhirType());
ElementDefinition ted = sd.getSnapshot().getElementFirstRep();
children.add(new ResourceElement(contextUtils, profileUtils, this, name, index, kind, v, sd, ted));
}
i++; i++;
} }
} }
@ -248,7 +300,7 @@ public class ResourceElement {
private ElementKind determineModelKind(Property p, Base v) { private ElementKind determineModelKind(Property p, Base v) {
if (v.isPrimitive()) { if (v.isPrimitive()) {
return ElementKind.PrimitiveType; return ElementKind.PrimitiveType;
} else if (context.isDatatype(v.fhirType())) { } else if (contextUtils.isDatatype(v.fhirType())) {
return ElementKind.DataType; return ElementKind.DataType;
} else if (!v.isResource()) { } else if (!v.isResource()) {
return ElementKind.BackboneElement; return ElementKind.BackboneElement;
@ -272,6 +324,25 @@ public class ResourceElement {
return children; return children;
} }
public List<NamedResourceElementList> childrenInGroups() {
loadChildren();
List<NamedResourceElementList> list = new ArrayList<ResourceElement.NamedResourceElementList>();
for (ResourceElement e : children) {
NamedResourceElementList nl = null;
for (NamedResourceElementList t : list) {
if (t.name.equals(e.name())) {
nl = t;
}
}
if (nl == null) {
nl = new NamedResourceElementList(e.name());
list.add(nl);
}
nl.values.add(e);
}
return list;
}
public List<ResourceElement> children(String name) { public List<ResourceElement> children(String name) {
loadChildren(); loadChildren();
List<ResourceElement> list = new ArrayList<ResourceElement>(); List<ResourceElement> list = new ArrayList<ResourceElement>();
@ -454,7 +525,7 @@ public class ResourceElement {
if (element != null) { if (element != null) {
return element instanceof DomainResource; return element instanceof DomainResource;
} else { } else {
return context.isDomainResource(fhirType()); return contextUtils.isDomainResource(fhirType());
} }
} }
@ -582,7 +653,7 @@ public class ResourceElement {
} }
public ContextUtilities getContextUtilities() { public ContextUtilities getContextUtilities() {
return context; return contextUtils;
} }
public boolean hasFormatComment() { public boolean hasFormatComment() {
@ -601,5 +672,13 @@ public class ResourceElement {
} }
} }
public StructureDefinition getClassDefinition() {
return classDefinition;
}
public ElementDefinition getPropertyDefinition() {
return propertyDefinition;
}
} }

View File

@ -7,6 +7,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.elementmodel.Manager;
@ -26,7 +27,7 @@ public class ResourceElementTests {
public void testDirect() throws FHIRFormatError, IOException { public void testDirect() throws FHIRFormatError, IOException {
IWorkerContext worker = TestingUtilities.getSharedWorkerContext(); IWorkerContext worker = TestingUtilities.getSharedWorkerContext();
Resource res = new XmlParser().parse(TestingUtilities.loadTestResource("r5", "bundle-resource-element-test.xml")); Resource res = new XmlParser().parse(TestingUtilities.loadTestResource("r5", "bundle-resource-element-test.xml"));
ResourceElement re = new ResourceElement(new ContextUtilities(worker), res); ResourceElement re = new ResourceElement(new ContextUtilities(worker), new ProfileUtilities(worker, null, null), res);
checkTree(re); checkTree(re);
} }
@ -34,7 +35,7 @@ public class ResourceElementTests {
public void testIndirect() throws FHIRFormatError, IOException { public void testIndirect() throws FHIRFormatError, IOException {
IWorkerContext worker = TestingUtilities.getSharedWorkerContext(); IWorkerContext worker = TestingUtilities.getSharedWorkerContext();
List<ValidatedFragment> res = Manager.parse(worker, TestingUtilities.loadTestResourceStream("r5", "bundle-resource-element-test.xml"), FhirFormat.XML); List<ValidatedFragment> res = Manager.parse(worker, TestingUtilities.loadTestResourceStream("r5", "bundle-resource-element-test.xml"), FhirFormat.XML);
ResourceElement re = new ResourceElement(new ContextUtilities(worker), res.get(0).getElement()); ResourceElement re = new ResourceElement(new ContextUtilities(worker), new ProfileUtilities(worker, null, null), res.get(0).getElement());
checkTree(re); checkTree(re);
} }