From 38587eb508fe15acb4cea93443716fcbfb2a31d2 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 13 Oct 2024 22:38:15 +0800 Subject: [PATCH] Render extensions on some data types, and fix rendering of complex data types when doing profile rendering --- .../conformance/profile/ProfileUtilities.java | 11 ++ .../hl7/fhir/r5/renderers/DataRenderer.java | 80 ++++++++---- .../r5/renderers/ProfileDrivenRenderer.java | 120 +++++++++++------- .../fhir/r5/renderers/ResourceRenderer.java | 3 +- 4 files changed, 146 insertions(+), 68 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java index a4bfb0e1b..b1e80f184 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java @@ -294,17 +294,28 @@ public class ProfileUtilities { public static class SourcedChildDefinitions { private StructureDefinition source; private List list; + private String path; public SourcedChildDefinitions(StructureDefinition source, List list) { super(); this.source = source; this.list = list; } + public SourcedChildDefinitions(StructureDefinition source, List list, String path) { + super(); + this.source = source; + this.list = list; + this.path = path; + } public StructureDefinition getSource() { return source; } public List getList() { return list; } + public String getPath() { + return path; + } + } public class ElementDefinitionResolution { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index 839648e4d..79980da72 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -41,6 +41,7 @@ import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent; +import org.hl7.fhir.r5.renderers.Renderer.RenderingStatus; 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.ResourceRendererMode; @@ -486,24 +487,45 @@ public class DataRenderer extends Renderer implements CodeResolver { // } // } // - public void renderExtensionsInText(RenderingStatus status, XhtmlNode div, ResourceWrapper element, String sep) throws FHIRFormatError, DefinitionException, IOException { + public void renderExtensionsInText(RenderingStatus status, XhtmlNode x, ResourceWrapper element, String sep) throws FHIRFormatError, DefinitionException, IOException { boolean first = true; for (ResourceWrapper ext : element.extensions()) { if (canRender(ext)) { + status.setExtensions(true); if (first) { first = false; } else { - div.tx(sep); - div.tx(" "); + x.tx(sep); + x.tx(" "); } String lbl = getExtensionLabel(ext); - div.tx(lbl); - div.tx(": "); - renderDataType(status, div, ext.child("value")); + x.tx(lbl); + x.tx(": "); + renderDataType(status, x, ext.child("value")); } } } + + + protected void checkRenderExtensions(RenderingStatus status, XhtmlNode x, ResourceWrapper element) throws FHIRFormatError, DefinitionException, IOException { + if (element.has("extension")) { + boolean someCanRender = false; + for (ResourceWrapper ext : element.children("extension")) { + ResourceWrapper value = ext.child("value"); + if (canRender(ext) && value.isPrimitive()) { + someCanRender = true; + } + } + if (someCanRender) { + status.setExtensions(true); + x.tx(" ("); + renderExtensionsInText(status, x, element, ", "); + x.tx(")"); + } + } + + } // public void renderExtensionsInList(XhtmlNode div, BackboneType element, String sep) throws FHIRFormatError, DefinitionException, IOException { // boolean first = true; @@ -742,13 +764,14 @@ public class DataRenderer extends Renderer implements CodeResolver { } public boolean canRenderDataType(String type) { - return context.getContextUtilities().isPrimitiveType(type) || Utilities.existsInList(type, "Annotation", "Coding", "CodeableConcept", "Identifier", "HumanName", "Address", + return context.getContextUtilities().isPrimitiveType(type) || Utilities.existsInList(type, "Annotation", "Coding", "CodeableConcept", "Identifier", "HumanName", "Address", "Dosage", "Expression", "Money", "ContactPoint", "Quantity", "Range", "Period", "Timing", "SampledData", "Reference", "UsageContext", "ContactDetail", "Ratio", "Attachment", "CodeableReference"); } public boolean renderDataType(RenderingStatus status, XhtmlNode x, ResourceWrapper type) throws FHIRFormatError, DefinitionException, IOException { return renderDataType(status, null, x, type); } + public boolean renderDataType(RenderingStatus status, XhtmlNode parent, XhtmlNode x, ResourceWrapper type) throws FHIRFormatError, DefinitionException, IOException { if (type == null) { return false; @@ -863,10 +886,11 @@ public class DataRenderer extends Renderer implements CodeResolver { renderUri(status, x, type); } - private void renderRatio(RenderingStatus status, XhtmlNode x, ResourceWrapper type) { + private void renderRatio(RenderingStatus status, XhtmlNode x, ResourceWrapper type) throws FHIRFormatError, DefinitionException, IOException { renderQuantity(status, x, type.child("numerator")); x.tx("/"); - renderQuantity(status, x, type.child("denominator")); + renderQuantity(status, x, type.child("denominator")); + checkRenderExtensions(status, x, type); } private void renderAttachment(RenderingStatus status, XhtmlNode x, ResourceWrapper att) { @@ -892,6 +916,7 @@ public class DataRenderer extends Renderer implements CodeResolver { private void renderDateTime(RenderingStatus status, XhtmlNode x, ResourceWrapper type) throws FHIRFormatError, DefinitionException, IOException { if (!renderPrimitiveWithNoValue(status, x, type)) { x.tx(displayDateTime(type)); + checkRenderExtensions(status, x, type); } } @@ -1002,7 +1027,11 @@ public class DataRenderer extends Renderer implements CodeResolver { return true; } - private String tail(String url) { + protected String tail(String url) { + return url.substring(url.lastIndexOf(".")+1); + } + + protected String utail(String url) { return url.contains("/") ? url.substring(url.lastIndexOf("/")+1) : url; } @@ -1038,7 +1067,8 @@ public class DataRenderer extends Renderer implements CodeResolver { } } } - } + } + checkRenderExtensions(status, x, uri); } protected void renderAnnotation(RenderingStatus status, XhtmlNode x, ResourceWrapper a) throws FHIRException { @@ -1270,7 +1300,7 @@ public class DataRenderer extends Renderer implements CodeResolver { return new CodeResolution(null, null, null, code.getText(), code.getText()); } } - protected void renderCodingWithDetails(RenderingStatus status, XhtmlNode x, ResourceWrapper c) { + protected void renderCodingWithDetails(RenderingStatus status, XhtmlNode x, ResourceWrapper c) throws FHIRFormatError, DefinitionException, IOException { String s = ""; if (c.has("display")) s = context.getTranslated(c.child("display")); @@ -1296,6 +1326,7 @@ public class DataRenderer extends Renderer implements CodeResolver { if (c.has("version")) { x.tx(" "+context.formatPhrase(RenderingContext.DATA_REND_VERSION, c.primitiveValue("version"), ")")); } + checkRenderExtensions(status, x, c); } protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c) { @@ -1434,7 +1465,8 @@ public class DataRenderer extends Renderer implements CodeResolver { } x.span(null, context.formatPhrase(RenderingContext.DATA_REND_CODES) +b.toString()).addText(s); - } + } + checkRenderExtensions(status, x, cc); } protected String displayIdentifier(ResourceWrapper ii) { @@ -1477,7 +1509,7 @@ public class DataRenderer extends Renderer implements CodeResolver { return s; } - protected void renderIdentifier(RenderingStatus status, XhtmlNode x, ResourceWrapper ii) { + protected void renderIdentifier(RenderingStatus status, XhtmlNode x, ResourceWrapper ii) throws FHIRFormatError, DefinitionException, IOException { if (ii.has("type")) { ResourceWrapper type = ii.child("type"); if (type.has("text")) { @@ -1527,7 +1559,8 @@ public class DataRenderer extends Renderer implements CodeResolver { x.tx(displayPeriod(ii.child("period"))); } x.tx(")"); - } + } + checkRenderExtensions(status, x, ii); } public static String displayHumanName(ResourceWrapper name) { @@ -1550,7 +1583,7 @@ public class DataRenderer extends Renderer implements CodeResolver { } - protected void renderHumanName(RenderingStatus status, XhtmlNode x, ResourceWrapper name) { + protected void renderHumanName(RenderingStatus status, XhtmlNode x, ResourceWrapper name) throws FHIRFormatError, DefinitionException, IOException { StringBuilder s = new StringBuilder(); if (name.has("text")) s.append(context.getTranslated(name.child("text"))); @@ -1567,7 +1600,8 @@ public class DataRenderer extends Renderer implements CodeResolver { if (name.has("use") && !name.primitiveValue("use").equals("usual")) { s.append("("+context.getTranslatedCode(name.primitiveValue("use"), "http://hl7.org/fhir/name-use")+")"); } - x.addText(s.toString()); + x.addText(s.toString()); + checkRenderExtensions(status, x, name); } private String displayAddress(ResourceWrapper address) { @@ -1604,8 +1638,9 @@ public class DataRenderer extends Renderer implements CodeResolver { return s.toString(); } - protected void renderAddress(RenderingStatus status, XhtmlNode x, ResourceWrapper address) { - x.addText(displayAddress(address)); + protected void renderAddress(RenderingStatus status, XhtmlNode x, ResourceWrapper address) throws FHIRFormatError, DefinitionException, IOException { + x.addText(displayAddress(address)); + checkRenderExtensions(status, x, address); } @@ -1788,7 +1823,7 @@ public class DataRenderer extends Renderer implements CodeResolver { return s.toString(); } - protected void renderQuantity(RenderingStatus status, XhtmlNode x, ResourceWrapper q) { + protected void renderQuantity(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws FHIRFormatError, DefinitionException, IOException { if (q.has("comparator")) x.addText(q.primitiveValue("comparator")); if (q.has("value")) { @@ -1805,7 +1840,8 @@ public class DataRenderer extends Renderer implements CodeResolver { } if (context.isTechnicalMode() && q.has("code")) { x.span("background: LightGoldenRodYellow", null).tx(" "+ (context.formatPhrase(RenderingContext.DATA_REND_DETAILS, displaySystem(q.primitiveValue("system")))) +q.primitiveValue("code")+" = '"+lookupCode(q.primitiveValue("system"), null, q.primitiveValue("code"))+"')"); - } + } + checkRenderExtensions(status, x, q); } @@ -2073,7 +2109,7 @@ public class DataRenderer extends Renderer implements CodeResolver { st = st + "-"+rep.primitiveValue("frequencyMax"); } if (rep.has("period")) { - st = st + " "+ (context.formatPhrase(RenderingContext.DATA_REND_PER))+rep.primitiveValue("period"); + st = st + " "+ (context.formatPhrase(RenderingContext.DATA_REND_PER))+" "+rep.primitiveValue("period"); if (rep.has("periodMax")) st = st + "-"+rep.primitiveValue("periodMax"); st = st + " "+displayTimeUnits(rep.primitiveValue("periodUnit")); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 0e0227efb..90b3d55ac 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -3,6 +3,7 @@ package org.hl7.fhir.r5.renderers; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -19,6 +20,7 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.SourcedElementDefinition; import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; import org.hl7.fhir.r5.renderers.utils.ResourceWrapper.NamedResourceWrapperList; @@ -49,7 +51,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } else { ElementDefinition ed = sd.getSnapshot().getElement().get(0); containedIds.clear(); - generateByProfile(status, r, sd, r, sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), context.isTechnicalMode(), 0); + generateByProfile(status, r, sd, r, ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), context.isTechnicalMode(), 0); } } catch (Exception e) { if (DEBUG) { @@ -159,7 +161,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { return null; } - private void renderLeaf(RenderingStatus status, ResourceWrapper res, ResourceWrapper ew, StructureDefinition sd, ElementDefinition defn, XhtmlNode parent, XhtmlNode x, boolean title, boolean showCodeDetails, Map displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { + private void renderLeaf(RenderingStatus status, ResourceWrapper res, ResourceWrapper ew, StructureDefinition sd, ElementDefinition defn, XhtmlNode parent, XhtmlNode x, boolean title, boolean showCodeDetails, Map displayHints, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { if (ew == null) return; @@ -173,7 +175,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } else if (!renderDataType(status, parent, x, ew)) { // well, we have a cell (x) to render this thing, whatever it is // it's not a data type for which we have a built rendering, so we're going to get a list of it's renderable datatype properties, and render them in a list - SourcedChildDefinitions childDefs = context.getProfileUtilities().getChildMap(sd, defn); + // SourcedChildDefinitions childDefs = context.getProfileUtilities().getChildMap(sd, defn); boolean first = true; x.tx(" ("); for (ResourceWrapper child : ew.children()) { @@ -199,24 +201,24 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } } - private boolean displayLeaf(ResourceWrapper res, ResourceWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, boolean allowLinks) throws FHIRException, UnsupportedEncodingException, IOException { - if (ew == null) - return false; - - Map displayHints = readDisplayHints(defn); - - if (name.endsWith("[x]")) - name = name.substring(0, name.length() - 3); - - if (!showCodeDetails && ew.isPrimitive() && isDefault(displayHints, ew)) { - return false; - } else if (Utilities.existsInList(ew.fhirType(), "Extension")) { - return false; - } else { - x.addText(name+": "+ displayDataType(ew)); - return true; - } - } +// private boolean displayLeaf(ResourceWrapper res, ResourceWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, boolean allowLinks) throws FHIRException, UnsupportedEncodingException, IOException { +// if (ew == null) +// return false; +// +// Map displayHints = readDisplayHints(defn); +// +// if (name.endsWith("[x]")) +// name = name.substring(0, name.length() - 3); +// +// if (!showCodeDetails && ew.isPrimitive() && isDefault(displayHints, ew)) { +// return false; +// } else if (Utilities.existsInList(ew.fhirType(), "Extension")) { +// return false; +// } else { +// x.addText(name+": "+ displayDataType(ew)); +// return true; +// } +// } @@ -250,7 +252,8 @@ public class ProfileDrivenRenderer extends ResourceRenderer { return code != null && (code.equals("Element") || code.equals("BackboneElement")); } - private List getChildrenForPath(StructureDefinition profile, List elements, String path) throws DefinitionException { + private SourcedChildDefinitions getChildrenForPath(StructureDefinition profile, String path) throws DefinitionException { + var elements = profile.getSnapshot().getElement(); // do we need to do a name reference substitution? for (ElementDefinition e : elements) { if (e.getPath().equals(path) && e.hasContentReference()) { @@ -279,45 +282,45 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } if (results.isEmpty() && t != null && t.getType().size() == 1) { StructureDefinition tsd = context.getWorker().fetchTypeDefinition(t.getTypeFirstRep().getWorkingCode()); - return getChildrenForPath(tsd, tsd.getSnapshot().getElement(), tsd.getType()); + return getChildrenForPath(tsd, tsd.getType()); } - return results; + return new SourcedChildDefinitions(profile, results, path); } - private void generateByProfile(RenderingStatus status, ResourceWrapper res, StructureDefinition profile, ResourceWrapper e, List allElements, ElementDefinition defn, List children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { + private void generateByProfile(RenderingStatus status, ResourceWrapper res, StructureDefinition profile, ResourceWrapper e, ElementDefinition defn, List children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { if (children.isEmpty()) { StructureDefinition sdt = context.getWorker().fetchTypeDefinition(e.fhirType()); if (sdt != null && (sdt.getKind() == StructureDefinitionKind.COMPLEXTYPE || sdt.getKind() == StructureDefinitionKind.PRIMITIVETYPE)) { - renderLeaf(status, res, e, profile, defn, x, x, false, showCodeDetails, readDisplayHints(defn), path, indent); + renderLeaf(status, res, e, profile, defn, x, x, false, showCodeDetails, readDisplayHints(defn), indent); } else { // we don't have anything to render? } } else { List pl = splitExtensions(profile, e.childrenInGroups()); for (NamedResourceWrapperList p : pl) { - generateForProperty(status, res, profile, allElements, children, x, path, showCodeDetails, indent, false, p); + generateForProperty(status, res, profile, children, x, path, showCodeDetails, indent, false, p); } for (NamedResourceWrapperList p : pl) { - generateForProperty(status, res, profile, allElements, children, x, path, showCodeDetails, indent, true, p); + generateForProperty(status, res, profile, children, x, path, showCodeDetails, indent, true, p); } } } private void generateForProperty(RenderingStatus status, ResourceWrapper res, StructureDefinition profile, - List allElements, List children, XhtmlNode x, String path, + List children, XhtmlNode x, String path, boolean showCodeDetails, int indent, boolean round2, NamedResourceWrapperList p) throws UnsupportedEncodingException, IOException, EOperationOutcome { if (!p.getValues().isEmpty()) { ElementDefinition child = getElementDefinition(children, path+"."+p.getName()); if (child != null) { if (!child.getBase().hasPath() || !child.getBase().getPath().startsWith("Resource.")) { - generateElementByProfile(status, res, profile, allElements, x, path, showCodeDetails, indent, p, child, round2); + generateElementByProfile(status, res, profile, x, path, showCodeDetails, indent, p, child, round2); } } } } - public void generateElementByProfile(RenderingStatus status, ResourceWrapper res, StructureDefinition profile, List allElements, XhtmlNode x, String path, + public void generateElementByProfile(RenderingStatus status, ResourceWrapper res, StructureDefinition profile, XhtmlNode x, String path, boolean showCodeDetails, int indent, NamedResourceWrapperList p, ElementDefinition child, boolean round2) throws UnsupportedEncodingException, IOException, EOperationOutcome { Map displayHints = readDisplayHints(child); if ("DomainResource.contained".equals(child.getBase().getPath())) { @@ -336,8 +339,8 @@ public class ProfileDrivenRenderer extends ResourceRenderer { if (isExt) { status.setExtensions(true); } - List grandChildren = getChildrenForPath(profile, allElements, path+"."+p.getName()); - filterGrandChildren(grandChildren, path+"."+p.getName(), p); + SourcedChildDefinitions grandChildren = getChildrenForPath(profile, path+"."+p.getName()); + filterGrandChildren(grandChildren.getList(), path+"."+p.getName(), p); if (p.getValues().size() > 0) { if (isSimple(child) && !isExt) { XhtmlNode para = x.isPara() ? para = x : x.para(); @@ -351,7 +354,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { if (renderAsList(child) && p.getValues().size() > 1) { XhtmlNode list = x.ul(); for (ResourceWrapper v : p.getValues()) - renderLeaf(status, res, v, profile, child, x, list.li(), false, showCodeDetails, displayHints, path, indent); + renderLeaf(status, res, v, profile, child, x, list.li(), false, showCodeDetails, displayHints, indent); } else { boolean first = true; for (ResourceWrapper v : p.getValues()) { @@ -360,23 +363,23 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } else { para.tx(", "); } - renderLeaf(status, res, v, profile, child, x, para, false, showCodeDetails, displayHints, path, indent); + renderLeaf(status, res, v, profile, child, x, para, false, showCodeDetails, displayHints, indent); } } } - } else if (canDoTable(path, p, grandChildren, x)) { + } else if (canDoTable(path, p, grandChildren.getList(), x)) { XhtmlNode xn = new XhtmlNode(NodeType.Element, getHeader()); xn.addText(Utilities.capitalize(Utilities.camelCase(Utilities.pluralizeMe(p.getName())))); XhtmlNode tbl = new XhtmlNode(NodeType.Element, "table"); tbl.setAttribute("class", "grid"); XhtmlNode tr = tbl.tr(); tr.td().style("display: none").tx("-"); // work around problem with empty table rows - boolean add = addColumnHeadings(tr, grandChildren); + boolean add = addColumnHeadings(tr, grandChildren.getList()); for (ResourceWrapper v : p.getValues()) { if (v != null) { tr = tbl.tr(); tr.td().style("display: none").tx("*"); // work around problem with empty table rows - add = addColumnValues(status, res, tr, profile, grandChildren, v, showCodeDetails, displayHints, path, indent) || add; + add = addColumnValues(status, res, tr, profile, grandChildren.getList(), v, showCodeDetails, displayHints, indent) || add; } } if (add) { @@ -393,7 +396,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { XhtmlNode para = x.para(); para.b().addText(labelforExtension(sd, p.getUrl())); para.tx(": "); - renderLeaf(status, res, vp, profile, child, x, para, false, showCodeDetails, displayHints, path, indent); + renderLeaf(status, res, vp, profile, child, x, para, false, showCodeDetails, displayHints, indent); } else if (!ev.isEmpty()) { XhtmlNode bq = x.addTag("blockquote"); bq.para().b().addText(labelforExtension(sd, p.getUrl())); @@ -410,13 +413,13 @@ public class ProfileDrivenRenderer extends ResourceRenderer { XhtmlNode li = ul.li(); li.tx(labelForSubExtension(vv.primitiveValue("url"), sd)); li.tx(": "); - renderLeaf(status, res, vv.child("value"), sd, child, x, li, isExt, showCodeDetails, displayHints, path, indent); + renderLeaf(status, res, vv.child("value"), sd, child, x, li, isExt, showCodeDetails, displayHints, indent); } } else { for (ResourceWrapper vv : ev) { StructureDefinition ex = context.getWorker().fetchTypeDefinition("Extension"); - List children = getChildrenForPath(profile, ex.getSnapshot().getElement(), "Extension"); - generateByProfile(status, res, ex, vv, allElements, child, children, bq, "Extension", showCodeDetails, indent+1); + SourcedChildDefinitions children = getChildrenForPath(ex, "Extension"); + generateByProfile(status, res, ex, vv, child, children.getList(), bq, "Extension", showCodeDetails, indent+1); } } } @@ -427,7 +430,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { if (v != null) { XhtmlNode bq = x.addTag("blockquote"); bq.para().b().addText(p.getName()); - generateByProfile(status, res, profile, v, allElements, child, grandChildren, bq, path+"."+p.getName(), showCodeDetails, indent+1); + generateByProfile(status, res, grandChildren.getSource(), v, child, grandChildren.getList(), bq, grandChildren.getPath(), showCodeDetails, indent+1); } } } @@ -435,6 +438,29 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } } +// +// private String getGrandChildBase(List grandChildren) { +// if (grandChildren == null || grandChildren.isEmpty()) { +// return null; +// } +// String[] path = grandChildren.get(0).getPath().split("\\."); +// for (int i = 1; i < grandChildren.size(); i++) { +// path = getSharedString(path, grandChildren.get(1).getPath().split("\\.")); +// } +// return CommaSeparatedStringBuilder.join(".", path); +// } +// +// private String[] getSharedString(String[] path, String[] path2) { +// int m = -1; +// for (int i = 0; i < Integer.min(path.length, path2.length); i++) { +// if (path[i].equals(path2[i])) { +// m = i; +// } else { +// break; +// } +// } +// return m == -1 ? new String[0] : Arrays.copyOfRange(path, 0, m+1); +// } private String labelForSubExtension(String url, StructureDefinition sd) { return url; @@ -530,7 +556,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { return b; } - private boolean addColumnValues(RenderingStatus status, ResourceWrapper res, XhtmlNode tr, StructureDefinition profile, List grandChildren, ResourceWrapper v, boolean showCodeDetails, Map displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { + private boolean addColumnValues(RenderingStatus status, ResourceWrapper res, XhtmlNode tr, StructureDefinition profile, List grandChildren, ResourceWrapper v, boolean showCodeDetails, Map displayHints, int indent) throws FHIRException, UnsupportedEncodingException, IOException, EOperationOutcome { boolean b = false; for (ElementDefinition e : grandChildren) { List p = v.children(e.getPath().substring(e.getPath().lastIndexOf(".")+1)); @@ -542,7 +568,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { for (ResourceWrapper vv : p) { b = true; td.sep(", "); - renderLeaf(status, res, vv, profile, e, td, td, false, showCodeDetails, displayHints, path, indent); + renderLeaf(status, res, vv, profile, e, td, td, false, showCodeDetails, displayHints, indent); } } } @@ -656,6 +682,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer { return path.substring(path.lastIndexOf(".")+1); } + protected String utail(String path) { + return path.contains("/") ? path.substring(path.lastIndexOf("/")+1) : path; + } + public boolean canRender(Resource resource) { return context.getWorker().getResourceNames().contains(resource.fhirType()); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java index ace526204..5bfafc50e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java @@ -35,7 +35,6 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.XVerExtensionManager; -import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; @@ -369,8 +368,10 @@ public abstract class ResourceRenderer extends DataRenderer { } else { x.tx("??"); } + checkRenderExtensions(status, x, type); } + public void renderReference(ResourceWrapper res, HierarchicalTableGenerator gen, List pieces, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException { if (r == null) { pieces.add(gen.new Piece(null, "null!", null));