FHIR-24884 Define best practices for narrative for a resource

This commit is contained in:
Grahame Grieve 2022-08-29 15:53:47 +10:00
parent 17adc621d3
commit 4db936752a
10 changed files with 108 additions and 13 deletions

View File

@ -6,6 +6,8 @@ import java.io.UnsupportedEncodingException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
@ -13,12 +15,13 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.LiquidEngine;
import org.hl7.fhir.r5.utils.LiquidEngine.ILiquidRenderingSupport;
import org.hl7.fhir.r5.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
public class LiquidRenderer extends ResourceRenderer {
public class LiquidRenderer extends ResourceRenderer implements ILiquidRenderingSupport {
private String liquidTemplate;
@ -56,6 +59,7 @@ public class LiquidRenderer extends ResourceRenderer {
XhtmlNode xn;
try {
engine.setIncludeResolver(new LiquidRendererIncludeResolver(context));
engine.setRenderingSupport(this);
LiquidDocument doc = engine.parse(liquidTemplate, "template");
String html = engine.evaluate(doc, r, rcontext);
xn = new XhtmlParser().parseFragment(html);
@ -102,4 +106,23 @@ public class LiquidRenderer extends ResourceRenderer {
return true;
}
public RendererType getRendererType() {
return RendererType.LIQUID;
}
@Override
public String renderForLiquid(Base base) throws FHIRException {
try {
if (base instanceof Element) {
return displayBase(context.getParser().parseType((Element) base));
} else {
return displayBase(base);
}
} catch (FHIRFormatError e) {
throw new FHIRException(e);
} catch (IOException e) {
throw new FHIRException(e);
}
}
}

View File

@ -207,7 +207,6 @@ public class ListRenderer extends ResourceRenderer {
}
}
private XhtmlNode shortForRef(XhtmlNode x, Base ref) throws UnsupportedEncodingException, IOException {
if (ref == null) {
x.tx("(null)");
@ -215,16 +214,20 @@ public class ListRenderer extends ResourceRenderer {
String disp = ref.getChildByName("display") != null && ref.getChildByName("display").hasValues() ? ref.getChildByName("display").getValues().get(0).primitiveValue() : null;
if (ref.getChildByName("reference").hasValues()) {
String url = ref.getChildByName("reference").getValues().get(0).primitiveValue();
ResourceWithReference r = context.getResolver().resolve(context, url);
if (r == null) {
if (disp == null) {
disp = url;
}
x.tx(disp);
} else if (r.getResource() != null) {
RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, (Reference) ref);
if (url.startsWith("#")) {
x.tx("?ngen-16a?");
} else {
RendererFactory.factory(url, context).renderReference(r.getResource(), x, (Reference) ref);
ResourceWithReference r = context.getResolver().resolve(context, url);
if (r == null) {
if (disp == null) {
disp = url;
}
x.tx(disp);
} else if (r.getResource() != null) {
RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, (Reference) ref);
} else {
x.ah(r.getReference()).tx(url);
}
}
} else if (disp != null) {
x.tx(disp);

View File

@ -1015,4 +1015,8 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
return context.getWorker().getResourceNames().contains(resource.fhirType());
}
public RendererType getRendererType() {
return RendererType.PROFILE;
}
}

View File

@ -5,6 +5,7 @@ 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.utilities.Utilities;
public class RendererFactory {
@ -131,5 +132,11 @@ public class RendererFactory {
return factory(rw, lrc, null);
}
public static boolean hasSpecificRenderer(String rt) {
return Utilities.existsInList(rt,
"CodeSystem", "ValueSet", "ConceptMap",
"CapabilityStatement", "CompartmentDefinition", "ImplementationGuide", "Library", "NamingSystem", "OperationDefinition", "Questionnaire", "SearchParameter", "StructureDefinition");
}
}

View File

@ -26,6 +26,7 @@ import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.utils.DirectWrappers.ResourceWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.ElementWrappers.ResourceWrapperMetaElement;
import org.hl7.fhir.r5.renderers.ResourceRenderer.RendererType;
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;
@ -39,6 +40,11 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public abstract class ResourceRenderer extends DataRenderer {
public enum RendererType {
NATIVE, PROFILE, LIQUID
}
protected ResourceContext rcontext;
protected XVerExtensionManager xverManager;
protected boolean forResource;
@ -507,4 +513,8 @@ public abstract class ResourceRenderer extends DataRenderer {
}
}
public RendererType getRendererType() {
return RendererType.NATIVE;
}
}

View File

@ -15,6 +15,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersion;
@ -38,6 +39,7 @@ public class RenderingContext {
// parses xml to an XML instance. Whatever codes provides this needs to provide something that parses the right version
public interface ITypeParser {
Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException ;
Base parseType(Element base) throws FHIRFormatError, IOException, FHIRException ;
}
/**

View File

@ -1,5 +1,6 @@
package org.hl7.fhir.r5.utils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -37,22 +38,31 @@ import java.util.Map;
*/
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.Tuple;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.utils.FHIRPathEngine.ExpressionNodeWithOffset;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.LiquidEngine.ILiquidRenderingSupport;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class LiquidEngine implements IEvaluationContext {
public interface ILiquidRenderingSupport {
String renderForLiquid(Base i) throws FHIRException;
}
public interface ILiquidEngineIncludeResolver {
public String fetchInclude(LiquidEngine engine, String name);
}
@ -60,6 +70,7 @@ public class LiquidEngine implements IEvaluationContext {
private IEvaluationContext externalHostServices;
private FHIRPathEngine engine;
private ILiquidEngineIncludeResolver includeResolver;
private ILiquidRenderingSupport renderingSupport;
private class LiquidEngineContext {
private Object externalContext;
@ -92,6 +103,14 @@ public class LiquidEngine implements IEvaluationContext {
this.includeResolver = includeResolver;
}
public ILiquidRenderingSupport getRenderingSupport() {
return renderingSupport;
}
public void setRenderingSupport(ILiquidRenderingSupport renderingSupport) {
this.renderingSupport = renderingSupport;
}
public LiquidDocument parse(String source, String sourceName) throws FHIRException {
return new LiquidParser(source).parse(sourceName);
}
@ -104,6 +123,7 @@ public class LiquidEngine implements IEvaluationContext {
}
return b.toString();
}
private abstract class LiquidNode {
protected void closeUp() {
@ -130,6 +150,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) {
b.append(constant);
}
}
private class LiquidStatement extends LiquidNode {
@ -140,7 +161,13 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null)
compiled = engine.parse(statement);
b.append(engine.evaluateToString(ctxt, resource, resource, resource, compiled));
List<Base> items = engine.evaluate(ctxt, resource, resource, resource, compiled);
boolean first = true;
for (Base i : items) {
if (first) first = false; else b.append(", ");
String s = renderingSupport != null ? renderingSupport.renderForLiquid(i) : null;
b.append(s != null ? s : engine.convertToString(i));
}
}
}

View File

@ -111,6 +111,10 @@ public class NarrativeGenerationTests {
public Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException {
return new org.hl7.fhir.r5.formats.XmlParser().parseType(xml, type);
}
@Override
public Base parseType(org.hl7.fhir.r5.elementmodel.Element e) throws FHIRFormatError, IOException, FHIRException {
throw new NotImplementedException();
}
}
public static final String WINDOWS = "WINDOWS";

View File

@ -9,6 +9,7 @@ import java.util.stream.Stream;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
@ -50,6 +51,11 @@ public class VocabTests {
public Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException {
return new org.hl7.fhir.r5.formats.XmlParser().parseType(xml, type);
}
@Override
public Base parseType(org.hl7.fhir.r5.elementmodel.Element e) throws FHIRFormatError, IOException, FHIRException {
throw new NotImplementedException();
}
}
private static IWorkerContext context;

View File

@ -1542,3 +1542,12 @@ v: {
"system" : "urn:iso:std:iso:3166"
}
-------------------------------------------------------------------------------------
{"code" : {
"code" : "en-AU"
}, "url": "http://hl7.org/fhir/ValueSet/languages", "version": "4.0.1", "lang":"en-AU", "useServer":"true", "useClient":"true", "guessSystem":"true", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}####
v: {
"display" : "English (Australia)",
"code" : "en-AU",
"system" : "urn:ietf:bcp:47"
}
-------------------------------------------------------------------------------------