liquid generation in narrative generator, render min/max value sets, fix broken links in IGs from relative references in links in markdown in core

This commit is contained in:
Grahame Grieve 2019-03-05 06:52:15 +11:00
parent 88c145a00c
commit 58b3ca2c88
44 changed files with 87 additions and 341 deletions

1
.gitignore vendored
View File

@ -156,3 +156,4 @@ local.properties
/org.hl7.fhir.r4/src/main/resources/graphql/*.out
/org.hl7.fhir.r4/src/main/resources/gen
/release_batch_template.txt
/org.hl7.fhir.r5/src/main/resources/graphql/*.out

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -246,6 +246,7 @@ public class ProfileUtilities extends TranslatingUtilities {
boolean hasLinkFor(String typeSimple);
String getLinkFor(String corePath, String typeSimple);
BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException;
BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException;
String getLinkForProfile(StructureDefinition profile, String url);
boolean prependLinks();
}
@ -2675,9 +2676,22 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null)));
if (binding.hasStrength()) {
c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, " (", null)));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition())));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition())));
c.getPieces().add(gen.new Piece(null, ")", null));
}
if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) {
br = pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), definition.getPath());
c.addPiece(gen.new Piece("br"));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"extension-elementdefinition-maxvalueset.html", translate("sd.table", "Max Binding")+": ", "Max Value Set Extension").addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null)));
}
if (binding.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) {
br = pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MIN_VALUESET), definition.getPath());
c.addPiece(gen.new Piece("br"));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"extension-elementdefinition-minvalueset.html", translate("sd.table", "Mon Binding")+": ", "Min Value Set Extension").addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null)));
}
}
for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) {
if (!inv.hasSource() || allInvariants) {

View File

@ -435,6 +435,11 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
return null;
}
@Override
public BindingResolution resolveBinding(StructureDefinition profile, String url, String path) {
return null;
}
@Override
public String getLinkForProfile(StructureDefinition profile, String url) {
return null;

View File

@ -78,7 +78,7 @@ public class LiquidEngine implements IEvaluationContext {
this.includeResolver = includeResolver;
}
public LiquidDocument parse(String source, String sourceName) throws Exception {
public LiquidDocument parse(String source, String sourceName) throws FHIRException {
return new LiquidParser(source).parse(sourceName);
}

View File

@ -63,6 +63,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.LinkedTransferQueue;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
@ -174,6 +175,9 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.r5.utils.NarrativeGenerator.ILiquidTemplateProvider;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
@ -188,6 +192,12 @@ import org.w3c.dom.Element;
public class NarrativeGenerator implements INarrativeGenerator {
public interface ILiquidTemplateProvider {
String findTemplate(ResourceContext rcontext, DomainResource r);
}
public interface ITypeParser {
Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException ;
}
@ -271,15 +281,12 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
return null;
}
}
private static final String ABSTRACT_CODE_HINT = "This code is not selectable ('Abstract')";
public interface IReferenceResolver {
ResourceWithReference resolve(String url);
}
private Bundle bundle;
@ -290,6 +297,8 @@ public class NarrativeGenerator implements INarrativeGenerator {
private ProfileKnowledgeProvider pkp;
private MarkDownProcessor markdown = new MarkDownProcessor(Dialect.COMMON_MARK);
private ITypeParser parser; // when generating for an element model
private ILiquidTemplateProvider templateProvider;
private IEvaluationContext services;
public boolean generate(Bundle b, boolean evenIfAlreadyHasNarrative, Set<String> outputTracker) throws EOperationOutcome, FHIRException, IOException {
boolean res = false;
@ -312,6 +321,12 @@ public class NarrativeGenerator implements INarrativeGenerator {
if (rcontext == null)
rcontext = new ResourceContext(null, r);
if (templateProvider != null) {
String liquidTemplate = templateProvider.findTemplate(rcontext, r);
if (liquidTemplate != null) {
return generateByLiquid(rcontext, r, liquidTemplate, outputTracker);
}
}
if (r instanceof ConceptMap) {
return generate(rcontext, (ConceptMap) r); // Maintainer = Grahame
} else if (r instanceof ValueSet) {
@ -350,6 +365,24 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
}
private boolean generateByLiquid(ResourceContext rcontext, DomainResource r, String liquidTemplate, Set<String> outputTracker) {
LiquidEngine engine = new LiquidEngine(context, services);
XhtmlNode x;
try {
LiquidDocument doc = engine.parse(liquidTemplate, "template");
String html = engine.evaluate(doc, r, rcontext);
x = new XhtmlParser().parseFragment(html);
if (!x.getName().equals("div"))
throw new FHIRException("Error in template: Root element is not 'div'");
} catch (FHIRException | IOException e) {
x = new XhtmlNode(NodeType.Element, "div");
x.para().b().setAttribute("style", "color: maroon").tx("Exception generating Narrative: "+e.getMessage());
}
inject(r, x, NarrativeStatus.GENERATED);
return true;
}
private interface PropertyWrapper {
public String getName();
public boolean hasValues();
@ -973,6 +1006,12 @@ public class NarrativeGenerator implements INarrativeGenerator {
this.basePath = basePath;
init();
}
public NarrativeGenerator setLiquidServices(ILiquidTemplateProvider templateProvider, IEvaluationContext services) {
this.templateProvider = templateProvider;
this.services = services;
return this;
}
public Base parseType(String xml, String type) throws IOException, FHIRException {
if (parser != null)

View File

@ -144,6 +144,7 @@ public class ToolingExtensions {
public static final String EXT_IGP_SPREADSHEET = "http://hl7.org/fhir/StructureDefinition/igpublisher-spreadsheet";
public static final String EXT_IGP_BUNDLE = "http://hl7.org/fhir/StructureDefinition/igpublisher-bundle";
public static final String EXT_MAX_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet";
public static final String EXT_MIN_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-minValueSet";
public static final String EXT_PROFILE_ELEMENT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-profile-element";

View File

@ -1,16 +0,0 @@
{
"identifier":[{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345"
}],
"active":true,
"name":[{
"given":["Peter","James"],
"family":"Chalmers"
},{
"given":["Jim"]
},{
"given":["Peter","James"],
"family":"Windsor"
}]
}

View File

@ -1,12 +0,0 @@
{
"active":true,
"name":[{
"given":["Peter","James"],
"family":"Chalmers"
},{
"given":["Jim"]
},{
"given":["Peter","James"],
"family":"Windsor"
}]
}

View File

@ -1,16 +0,0 @@
{
"identifier":[{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345"
}],
"active":true,
"name":[{
"given":["Peter","James"],
"family":"Chalmers"
},{
"given":["Jim"]
},{
"given":["Peter","James"],
"family":"Windsor"
}]
}

View File

@ -1,7 +0,0 @@
{
"id":"glossy",
"extension":[{
"url":"http://example.org/StructureDefinition/trials",
"valueCode":"renal"
}]
}

View File

@ -1,7 +0,0 @@
{
"id":"glossy",
"extension":[{
"url":"http://example.org/StructureDefinition/trials",
"valueCode":"renal"
}]
}

View File

@ -1,15 +0,0 @@
{
"subject":[{
"resource":{
"birthDate":"2016-05-18"
}
},{
"resource":{
"_birthDate":{
"extension":[{
"valueDateTime":"2016-05-18T10:28:45Z"
}]
}
}
}]
}

View File

@ -1,14 +0,0 @@
{
"identifier":[{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345"
}],
"active":true,
"name":[{
"given":["Peter","James"],
"family":"Chalmers"
},{
"given":["Peter","James"],
"family":"Windsor"
}]
}

View File

@ -1,7 +0,0 @@
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given":["Peter","Jim","Peter"],
"family":["Chalmers","Windsor"]
}

View File

@ -1,7 +0,0 @@
{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345",
"active":true,
"given":["Peter","James","Jim","Peter","James"],
"family":["Chalmers","Windsor"]
}

View File

@ -1,7 +0,0 @@
{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345",
"active":true,
"given":["Peter","James"],
"family":"Chalmers"
}

View File

@ -1,10 +0,0 @@
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given.official":["Peter","James"],
"family.official":"Chalmers",
"given.usual":["Jim"],
"given.maiden":["Peter","James"],
"family.maiden":"Windsor"
}

View File

@ -1,10 +0,0 @@
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given.0":["Peter","James"],
"family.0":"Chalmers",
"given.1":["Jim"],
"given.2":["Peter","James"],
"family.2":"Windsor"
}

View File

@ -1,7 +0,0 @@
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given":["Peter","James","Jim","Peter","James"],
"family":["Chalmers","Windsor"]
}

View File

@ -1,23 +0,0 @@
{
"entry":[{
"item":{
"reference":"Patient/1"
}
},{
"item":{
"reference":"Patient/2"
}
},{
"item":{
"reference":"Patient/3"
}
},{
"item":{
"reference":"Patient/4"
}
},{
"item":{
"reference":"Patient/5"
}
}]
}

View File

@ -1,9 +0,0 @@
{
"subject":{
"reference":"Patient/example"
},
"valueQuantity":{
"value":185,
"unit":"lbs"
}
}

View File

@ -1,24 +0,0 @@
{
"id":"example",
"subject":{
"reference":"Patient/example",
"resource":{
"active":true
}
},
"code":{
"coding":[{
"system":"http://loinc.org",
"code":"29463-7"
},{
"system":"http://loinc.org",
"code":"3141-9"
},{
"system":"http://snomed.info/sct",
"code":"27113001"
},{
"system":"http://acme.org/devices/clinical-codes",
"code":"body-weight"
}]
}
}

View File

@ -1,5 +0,0 @@
{
"authorizingPrescription":[{
"reference":"MedicationRequest/medrx0330"
}]
}

View File

@ -1,6 +0,0 @@
{
"id":"example",
"ConditionList":[{
"id":"example"
}]
}

View File

@ -1,24 +0,0 @@
{
"id":"example",
"subject":{
"reference":"Patient/example",
"resource":{
"active":true
}
},
"code":{
"coding":[{
"system":"http://loinc.org",
"code":"29463-7"
},{
"system":"http://loinc.org",
"code":"3141-9"
},{
"system":"http://snomed.info/sct",
"code":"27113001"
},{
"system":"http://acme.org/devices/clinical-codes",
"code":"body-weight"
}]
}
}

View File

@ -1,21 +0,0 @@
{
"id":"example",
"subject":{
"reference":"Patient/example"
},
"code":{
"coding":[{
"system":"http://loinc.org",
"code":"29463-7"
},{
"system":"http://loinc.org",
"code":"3141-9"
},{
"system":"http://snomed.info/sct",
"code":"27113001"
},{
"system":"http://acme.org/devices/clinical-codes",
"code":"body-weight"
}]
}
}

View File

@ -1,24 +0,0 @@
{
"id":"example",
"subject":{
"reference":"Patient/example",
"resource":{
"active":true
}
},
"code":{
"coding":[{
"system":"http://loinc.org",
"code":"29463-7"
},{
"system":"http://loinc.org",
"code":"3141-9"
},{
"system":"http://snomed.info/sct",
"code":"27113001"
},{
"system":"http://acme.org/devices/clinical-codes",
"code":"body-weight"
}]
}
}

View File

@ -1,21 +0,0 @@
{
"PatientConnection":{
"count":50,
"offset":0,
"pagesize":50,
"edges":[{
"resource":{
"id":"example",
"active":true
}
},{
"mode":"match",
"score":0.5,
"resource":{
"id":"xds",
"active":true
}
}],
"next":"77c97e03-8a6c-415f-a63d-11c80cf73f:50"
}
}

View File

@ -1,9 +0,0 @@
{
"PatientList":[{
"id":"example",
"active":true
},{
"id":"xds",
"active":true
}]
}

View File

@ -1,6 +0,0 @@
{
"Patient":{
"id":"example",
"active":true
}
}

View File

@ -1,16 +0,0 @@
{
"identifier":[{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345"
}],
"active":true,
"name":[{
"given":["Peter","James"],
"family":"Chalmers"
},{
"given":["Jim"]
},{
"given":["Peter","James"],
"family":"Windsor"
}]
}

View File

@ -90,6 +90,14 @@ public class SnapShotGenerationTests {
return br;
}
@Override
public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException {
BindingResolution br = new BindingResolution();
br.url = path+"/something.html";
br.display = "something";
return br;
}
@Override
public String getLinkForProfile(StructureDefinition profile, String url) {
StructureDefinition sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url);

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4400,5 +4400,9 @@ private String misplacedItemError(QuestionnaireItemComponent qItem) {
return expr;
}
public IEvaluationContext getExternalHostServices() {
return externalHostServices;
}
}

View File

@ -13,7 +13,7 @@
each other. It is fine to bump the point version of this POM without affecting
HAPI FHIR.
-->
<version>3.7.8-SNAPSHOT</version>
<version>3.7.9-SNAPSHOT</version>
<properties>
<hapi_fhir_version>3.7.0-SNAPSHOT</hapi_fhir_version>