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 {
render(x, new DirectWrappers.ResourceWrapperDirect(this.context, dr));
for (Resource resource : dr.getContained()) {
x.hr();
RendererFactory.factory(resource, context).render(x, resource);
}
return true;
}
@ -461,7 +466,9 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
td = tr.td();
pw = getProperty(obs, "note");
if (valued(pw)) {
render(td, pw.value());
for (BaseWrapper b : pw.getValues()) {
render(td, b);
}
}
}
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.ElementWrappers;
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;
@ -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) {
XhtmlNode div = res.getNarrative();
if (div != null) {

View File

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

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.r5.renderers;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.HashMap;
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.Narrative;
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.Reference;
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.RenderingContext;
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.ResourceWithReference;
import org.hl7.fhir.r5.renderers.utils.ResourceElement;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
@ -54,7 +56,6 @@ public abstract class ResourceRenderer extends DataRenderer {
}
protected ResourceContext rcontext;
protected XVerExtensionManager xverManager;
protected boolean multiLangMode;
@ -62,21 +63,6 @@ public abstract class ResourceRenderer extends DataRenderer {
public ResourceRenderer(RenderingContext 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() {
return multiLangMode;
@ -87,13 +73,16 @@ public abstract class ResourceRenderer extends DataRenderer {
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");
render(x, dr);
renderResource(new RenderingStatus(), x, dr);
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
*
@ -101,39 +90,33 @@ public abstract class ResourceRenderer extends DataRenderer {
* @throws EOperationOutcome
* @throws FHIRException
*/
public void renderResource(DomainResource r) throws IOException, FHIRException, EOperationOutcome {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
RenderingStatus status = new RenderingStatus();
renderResource(status, x, r);
String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) {
if (!hasAnchorName(x, an)) {
injectAnchorName(x, an);
}
}
inject(r, x, status.getExtensions() ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public void render(DomainResource r) throws IOException, FHIRException, EOperationOutcome {
public void renderResource(ResourceElement r) throws IOException, FHIRException, EOperationOutcome {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions;
hasExtensions = render(x, r);
RenderingStatus status = new RenderingStatus();
renderResource(status, x, r);
String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) {
if (!hasAnchorName(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 {
assert r.getContext() == context;
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, r);
String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) {
if (!hasAnchorName(x, an)) {
injectAnchorName(x, an);
}
}
if (r.hasNarrative()) {
r.injectNarrative(this, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
return x;
}
public XhtmlNode checkNarrative(ResourceWrapper r) throws IOException, FHIRException, EOperationOutcome {
assert r.getContext() == context;
public XhtmlNode checkNarrative(ResourceElement r) throws IOException, FHIRException, EOperationOutcome {
XhtmlNode x = r.getNarrative();
String an = r.fhirType()+"_"+r.getId();
if (context.isAddName()) {
@ -166,24 +149,35 @@ public abstract class ResourceRenderer extends DataRenderer {
return false;
}
public abstract boolean render(XhtmlNode x, Resource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome;
public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
ProfileDrivenRenderer pr = new ProfileDrivenRenderer(context);
return pr.render(x, r);
// 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 String canonicalTitle(ResourceElement 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 {
x.tx(display(r));
public void describe(XhtmlNode x, ResourceElement r) throws UnsupportedEncodingException, IOException {
x.tx(displayDataType(r));
}
public void inject(ResourceElement r, XhtmlNode x, NarrativeStatus status) {
r.setNarrative(x, status.toCode(), multiLangMode, context.getLocale());
}
public void describe(XhtmlNode x, ResourceWrapper r) throws UnsupportedEncodingException, IOException {
x.tx(display(r));
}
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) {
r.getText().setUserData("renderer.generated", true);
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 {
ResourceWrapper rw = new ResourceWrapperDirect(this.context, res);
renderCanonical(rw, x, url);
}
public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url) throws UnsupportedEncodingException, IOException {
renderCanonical(rw, x, url, true, rw.getResource());
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");
}
public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url, boolean allowLinks, Resource src) throws UnsupportedEncodingException, IOException {
public void renderCanonical(ResourceElement res, XhtmlNode x, String url) throws UnsupportedEncodingException, IOException {
renderCanonical(res, x, url, true, res);
}
public void renderCanonical(ResourceElement rw, XhtmlNode x, String url, boolean allowLinks, ResourceElement src) throws UnsupportedEncodingException, IOException {
if (url == null) {
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)) {
x.code().tx(url);
} else {
@ -249,56 +246,65 @@ public abstract class ResourceRenderer extends DataRenderer {
}
}
public void render(Resource res, XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException {
if (type instanceof Reference) {
renderReference(res, x, (Reference) type);
} else if (type instanceof CodeableReference) {
CodeableReference cr = (CodeableReference) type;
if (cr.hasReference()) {
renderReference(res, x, cr.getReference());
public void renderReference(RenderingStatus status, ResourceElement res, XhtmlNode x, ResourceElement type) throws FHIRFormatError, DefinitionException, IOException {
if (type.fhirType().equals("Reference")) {
renderReference(status, res, x, type);
} else if (type.fhirType().equals("CodeableReference")) {
if (type.has("reference")) {
renderReference(status, res, x, type, true);
} else {
render(x, type);
renderDataType(status, x, type);
}
} 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) {
renderReference(res, x, (Reference) type);
} else if (type instanceof CodeableReference) {
CodeableReference cr = (CodeableReference) type;
if (cr.hasReference()) {
renderReference(res, x, cr.getReference());
/*
* } else if (ew.fhirType().equals("Reference")) {
Reference r = (Reference) e;
if (r.getReference() != null && r.getReference().contains("#")) {
if (containedIds.contains(r.getReference().substring(1))) {
x.ah("#hc"+r.getReference().substring(1)).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 {
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 {
render(x, type);
}
} else {
render(x, type);
}
}
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);
}
renderReference(res, x, r);
}
*/
public void renderReference(Resource res, HierarchicalTableGenerator gen, List<Piece> pieces, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException {
if (r == null) {
pieces.add(gen.new Piece(null, "null!", null));
return;
}
ResourceWrapper rw = new ResourceWrapperDirect(this.context, res);
ResourceWithReference tr = null;
String link = null;
StringBuilder text = new StringBuilder();
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 (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
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 (!Utilities.noString(r.getReference())) {
text.append(r.getReference());
} else if (r.hasIdentifier()) {
text.append(displayIdentifier(r.getIdentifier()));
text.append(displayIdentifier(new ResourceElement(context.getContextUtilities(), context.getProfileUtilities(), r.getIdentifier())));
} else {
text.append("??");
}
@ -364,7 +370,31 @@ public abstract class ResourceRenderer extends DataRenderer {
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) {
x.tx("null!");
return;
@ -372,10 +402,11 @@ public abstract class ResourceRenderer extends DataRenderer {
XhtmlNode c = null;
ResourceWithReference tr = null;
boolean onPage = false;
if (r.hasReferenceElement() && allowLinks) {
tr = resolveReference(rw, r.getReference());
String rref = r.primitiveValue("reference");
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.getReference().startsWith("#")) {
onPage = true;
@ -387,16 +418,16 @@ public abstract class ResourceRenderer extends DataRenderer {
} else {
c = x.ah(tr.getReference());
}
} else if (r.getReference().contains("?")) {
} else if (rref.contains("?")) {
x.tx(context.formatPhrase(RenderingContext.RES_REND_COND_REF)+" ");
c = x.code("");
} else {
c = x.ah(r.getReference());
c = x.ah(rref);
}
} else if ("#".equals(r.getReference())) {
} else if ("#".equals(rref)) {
c = x.ah("#");
} 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;
} else {
c = x;
@ -408,19 +439,19 @@ public abstract class ResourceRenderer extends DataRenderer {
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
String display = r.hasDisplayElement() ? r.getDisplay() : null;
String name = tr != null && tr.getResource() != null ? tr.getResource().getNameFromResource() : null;
String display = r.has("display") ? r.primitiveValue("display") : null;
String name = tr != null && tr.getResource() != null ? getNameForResource(tr.getResource()) : null;
if (display == null && (tr == null || tr.getResource() == null)) {
if (!Utilities.noString(r.getReference())) {
c.addText(r.getReference());
} else if (r.hasIdentifier()) {
renderIdentifier(c, r.getIdentifier());
if (!Utilities.noString(rref)) {
c.addText(rref);
} else if (r.has("identifier")) {
renderIdentifier(status, c, r.child("identifier"));
} else {
c.addText("??");
}
} else if (context.isTechnicalMode()) {
c.addText(r.getReference());
c.addText(rref);
if (display != null) {
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)) {
x.addText("(");
for (Extension ex : r.getExtensionsByUrl(ToolingExtensions.EXT_TARGET_ID)) {
if (ex.hasValue()) {
for (ResourceElement ex : r.extensions(ToolingExtensions.EXT_TARGET_ID)) {
if (ex.has("value")) {
x.sep(", ");
x.addText("#"+ex.getValue().primitiveValue());
x.addText("#"+ex.primitiveValue("value"));
}
}
for (Extension ex : r.getExtensionsByUrl(ToolingExtensions.EXT_TARGET_PATH)) {
if (ex.hasValue()) {
for (ResourceElement ex : r.extensions(ToolingExtensions.EXT_TARGET_PATH)) {
if (ex.has("value")) {
x.sep(", ");
x.addText("/#"+ex.getValue().primitiveValue());
x.addText("/#"+ex.primitiveValue("value"));
}
}
x.addText(")");
@ -451,48 +482,48 @@ public abstract class ResourceRenderer extends DataRenderer {
} else {
c.tx(context.formatPhrase(RenderingContext.RES_REND_GEN_SUM)+" ");
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 {
// 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) {
protected ResourceWithReference resolveReference(ResourceElement res, String url) {
if (url == null)
return null;
if (url.startsWith("#") && res != null) {
for (ResourceWrapper r : res.getContained()) {
for (ResourceElement r : res.children("contained")) {
if (r.getId().equals(url.substring(1)))
return new ResourceWithReference(ResourceReferenceKind.CONTAINED, url, r);
}
@ -503,7 +534,7 @@ public abstract class ResourceRenderer extends DataRenderer {
version = url.substring(url.indexOf("/_history/")+10);
url = url.substring(0, url.indexOf("/_history/"));
}
/*
if (rcontext != null) {
BundleEntryComponent bundleResource = rcontext.resolve(url);
if (bundleResource != null) {
@ -512,7 +543,7 @@ public abstract class ResourceRenderer extends DataRenderer {
id = makeIdFromBundleEntry(bundleResource.getFullUrl());
}
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);
if (bundleElement != null) {
@ -527,13 +558,13 @@ public abstract class ResourceRenderer extends DataRenderer {
} else {
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);
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) {
return context.getResolver().resolve(context, url);
} else
@ -570,14 +601,6 @@ public abstract class ResourceRenderer extends DataRenderer {
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) {
for (PropertyWrapper t : res.children()) {
if (t.getName().equals(name))
@ -591,18 +614,18 @@ public abstract class ResourceRenderer extends DataRenderer {
}
protected ResourceWrapper fetchResource(BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException {
if (context.getResolver() == null)
return null;
PropertyWrapper ref = subject.getChildByName("reference");
if (ref == null || !ref.hasValues()) {
return null;
}
String url = ref.value().getBase().primitiveValue();
ResourceWithReference rr = context.getResolver().resolve(context, url);
return rr == null ? null : rr.getResource();
}
// protected ResourceElement fetchResource(BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException {
// if (context.getResolver() == null)
// return null;
//
// PropertyWrapper ref = subject.getChildByName("reference");
// if (ref == null || !ref.hasValues()) {
// return null;
// }
// String url = ref.value().getBase().primitiveValue();
// ResourceWithReference rr = context.getResolver().resolve(context, url);
// return rr == null ? null : rr.getResource();
// }
protected String describeStatus(PublicationStatus status, boolean experimental) {
@ -637,22 +660,23 @@ public abstract class ResourceRenderer extends DataRenderer {
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")
.style("margin: 4px").style("border: 1px solid #8da1b4")
.style("border-radius: 5px").style("line-height: 60%");
String id = getPrimitiveValue(r, "id");
RenderingStatus status = new RenderingStatus();
String id = r.primitiveValue("id");
if (doId) {
div.an("hc"+id);
}
String lang = getPrimitiveValue(r, "language");
String ir = getPrimitiveValue(r, "implicitRules");
BaseWrapper meta = r.getChildByName("meta").hasValues() ? r.getChildByName("meta").getValues().get(0) : null;
String versionId = getPrimitiveValue(meta, "versionId");
String lastUpdated = getPrimitiveValue(meta, "lastUpdated");
String source = getPrimitiveValue(meta, "source");
String lang = r.primitiveValue("language");
String ir = r.primitiveValue("implicitRules");
ResourceElement meta = r.has("meta") && r.child("meta").isEmpty() ? r.child("meta") : null;
ResourceElement versionId = meta == null ? null : meta.child("versionId");
ResourceElement lastUpdated = meta == null ? null : meta.child("lastUpdated");
ResourceElement source = meta == null ? null : meta.child("source");
if (id != null || lang != null || versionId != null || lastUpdated != null) {
XhtmlNode p = plateStyle(div.para());
@ -667,7 +691,7 @@ public abstract class ResourceRenderer extends DataRenderer {
}
if (lastUpdated != null) {
p.tx(context.formatPhrase(RenderingContext.RES_REND_UPDATED) + "\"");
renderDateTime(p, lastUpdated);
renderDataType(status, p, lastUpdated);
p.tx("\" ");
}
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+"!");
}
if (meta != null) {
PropertyWrapper pl = meta.getChildByName("profile");
if (pl.hasValues()) {
List<ResourceElement> items = meta.children("profile");
if (!items.isEmpty()) {
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;
for (BaseWrapper bw : pl.getValues()) {
for (ResourceElement bw : items) {
if (first) first = false; else p.tx(", ");
renderCanonical(r, p, bw.getBase().primitiveValue());
renderCanonical(r, p, bw.primitiveValue());
}
}
PropertyWrapper tl = meta.getChildByName("tag");
if (tl.hasValues()) {
items = meta.children("tag");
if (!items.isEmpty()) {
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;
for (BaseWrapper bw : tl.getValues()) {
for (ResourceElement bw : items) {
if (first) first = false; else p.tx(", ");
String system = getPrimitiveValue(bw, "system");
String version = getPrimitiveValue(bw, "version");
String code = getPrimitiveValue(bw, "system");
String display = getPrimitiveValue(bw, "system");
renderCoding(p, new Coding(system, version, code, display));
renderCoding(status, p, bw);
}
}
PropertyWrapper sl = meta.getChildByName("security");
if (sl.hasValues()) {
items = meta.children("security");
if (!items.isEmpty()) {
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;
for (BaseWrapper bw : sl.getValues()) {
for (ResourceElement bw : items) {
if (first) first = false; else p.tx(", ");
String system = getPrimitiveValue(bw, "system");
String version = getPrimitiveValue(bw, "version");
String code = getPrimitiveValue(bw, "system");
String display = getPrimitiveValue(bw, "system");
renderCoding(p, new Coding(system, version, code, display));
renderCoding(status, p, bw);
}
}
}
@ -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;
}
public void renderOrError(DomainResource dr) {
try {
render(dr);
} catch (Exception e) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.para().tx(context.formatPhrase(RenderingContext.RES_REND_ERROR, e.getMessage())+" ");
dr.setText(null);
inject(dr, x, NarrativeStatus.GENERATED);
}
}
// public void renderOrError(DomainResource dr) {
// try {
// render(dr);
// } catch (Exception e) {
// XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
// x.para().tx(context.formatPhrase(RenderingContext.RES_REND_ERROR, e.getMessage())+" ");
// dr.setText(null);
// inject(dr, x, NarrativeStatus.GENERATED);
// }
//
// }
public RendererType getRendererType() {
return RendererType.NATIVE;
}
public class TableRowData {
private Map<String, List<DataType>> cols = new HashMap<>();
private Map<String, List<ResourceElement>> cols = new HashMap<>();
private TableData data;
public void value(String name, DataType value) {
public void value(String name, ResourceElement value) {
if (!cols.containsKey(name)) {
cols.put(name, new ArrayList<>());
}
@ -769,7 +785,7 @@ public abstract class ResourceRenderer extends DataRenderer {
return cols.containsKey(name);
}
public List<DataType> get(String name) {
public List<ResourceElement> get(String 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<>();
for (String name : provider.getColumns()) {
boolean hasData = false;
@ -830,11 +846,11 @@ public abstract class ResourceRenderer extends DataRenderer {
for (String col : columns) {
XhtmlNode td = tr.td();
boolean first = true;
List<DataType> list = row.get(col);
List<ResourceElement> list = row.get(col);
if (list != null) {
for (DataType value : list) {
for (ResourceElement value : list) {
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

@ -34,7 +34,8 @@ import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
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.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.AdditionalBindingPurposeVS;
@ -70,13 +71,15 @@ import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.InternalMarkdownProcessor;
import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.RenderStyle;
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.GenerationRules;
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.Resolver.ResourceContext;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.renderers2.Renderer.RenderingStatus;
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.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
@ -101,6 +104,27 @@ import org.hl7.fhir.utilities.xhtml.XhtmlParser;
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 {
}
@ -302,16 +326,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
private Map<String, Map<String, ElementDefinition>> sdMapCache = new HashMap<>();
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() {
return sdMapCache;
@ -329,18 +343,15 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
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) {
renderDict(sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, "");
} else {
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, ""));
}
return true;
status.setExtensions(true);
}
public void describe(XhtmlNode x, StructureDefinition sd) {
@ -351,10 +362,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return sd.present();
}
@Override
public String display(Resource r) throws UnsupportedEncodingException, IOException {
return ((StructureDefinition) r).present();
}
public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
if (r.has("title")) {

View File

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

View File

@ -6,16 +6,18 @@ import java.util.List;
import java.util.Locale;
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.elementmodel.Element;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DataType;
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.Property;
import org.hl7.fhir.r5.model.Resource;
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.XhtmlNode;
@ -34,47 +36,78 @@ public class ResourceElement {
BundleEntry,
IndependentResource
}
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 context;
private ContextUtilities contextUtils;
private ProfileUtilities profileUtils;
private ResourceElement parent;
private String name; // null at root
private int index; // -1 if not repeating
private ElementKind kind;
private StructureDefinition classDefinition;
private ElementDefinition propertyDefinition;
private Base element;
private Element model;
private List<ResourceElement> children;
public ResourceElement(ContextUtilities context, Resource resource) {
this.context = context;
public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, Resource resource) {
this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = null;
this.name = null;
this.index = -1;
this.kind = ElementKind.IndependentResource;
this.element = resource;
this.classDefinition = profileUtils.getContext().fetchTypeDefinition(resource.fhirType());
this.propertyDefinition = this.classDefinition.getSnapshot().getElementFirstRep();
}
public ResourceElement(ContextUtilities context, DataType type) {
this.context = context;
public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, DataType type) {
this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = null;
this.name = null;
this.index = -1;
this.kind = null;
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) {
this.context = context;
public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, ResourceElement parent, String name, int index, ElementKind kind, Base element, StructureDefinition classDefinition, ElementDefinition propertyDefinition) {
this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = parent;
this.name = name;
this.index = index;
this.kind = kind;
this.element = element;
this.classDefinition = classDefinition;
this.propertyDefinition = propertyDefinition;
}
public ResourceElement(ContextUtilities context, Element resource) {
this.context = context;
public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, Element resource) {
this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = null;
this.name = null;
this.index = -1;
@ -82,13 +115,16 @@ public class ResourceElement {
this.model = resource;
}
public ResourceElement(ContextUtilities context, ResourceElement parent, String name, int index, ElementKind kind, Element em) {
this.context = context;
public ResourceElement(ContextUtilities contextUtils, ProfileUtilities profileUtils, ResourceElement parent, String name, int index, ElementKind kind, Element em) {
this.contextUtils = contextUtils;
this.profileUtils = profileUtils;
this.parent = parent;
this.name = name;
this.index = index;
this.kind = kind;
this.model = em;
this.classDefinition = em.getProperty().getStructure();
this.propertyDefinition = em.getProperty().getDefinition();
}
public String fhirVersion() {
@ -201,7 +237,7 @@ public class ResourceElement {
String name = child.getProperty().isChoice() ? child.getProperty().getName() : child.getName();
int index = child.isList() ? child.getIndex() : -1;
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() {
SourcedChildDefinitions childDefs = propertyDefinition == null ? null : profileUtils.getChildMap(classDefinition, propertyDefinition);
for (Property p : element.children()) {
String name = p.getName();
int i = 0;
for (Base v : p.getValues()) {
ElementKind kind = determineModelKind(p, v);
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++;
}
}
@ -248,7 +300,7 @@ public class ResourceElement {
private ElementKind determineModelKind(Property p, Base v) {
if (v.isPrimitive()) {
return ElementKind.PrimitiveType;
} else if (context.isDatatype(v.fhirType())) {
} else if (contextUtils.isDatatype(v.fhirType())) {
return ElementKind.DataType;
} else if (!v.isResource()) {
return ElementKind.BackboneElement;
@ -272,6 +324,25 @@ public class ResourceElement {
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) {
loadChildren();
List<ResourceElement> list = new ArrayList<ResourceElement>();
@ -454,7 +525,7 @@ public class ResourceElement {
if (element != null) {
return element instanceof DomainResource;
} else {
return context.isDomainResource(fhirType());
return contextUtils.isDomainResource(fhirType());
}
}
@ -582,7 +653,7 @@ public class ResourceElement {
}
public ContextUtilities getContextUtilities() {
return context;
return contextUtils;
}
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 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.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager;
@ -26,7 +27,7 @@ public class ResourceElementTests {
public void testDirect() throws FHIRFormatError, IOException {
IWorkerContext worker = TestingUtilities.getSharedWorkerContext();
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);
}
@ -34,7 +35,7 @@ public class ResourceElementTests {
public void testIndirect() throws FHIRFormatError, IOException {
IWorkerContext worker = TestingUtilities.getSharedWorkerContext();
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);
}