Narrative fixes
This commit is contained in:
parent
80c13494a8
commit
ec2326b1f2
|
@ -583,6 +583,23 @@ public class Encounter extends BaseResource implements IResource {
|
||||||
return myType;
|
return myType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value(s) for <b>type</b> (Specific type of encounter).
|
||||||
|
* creating it if it does
|
||||||
|
* not exist. Will not return <code>null</code>.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>Definition:</b>
|
||||||
|
* Specific type of encounter (e.g. e-mail consultation, surgical day-care, skilled nursing, rehabilitation)
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public BoundCodeableConceptDt<EncounterTypeEnum> getTypeFirstRep() {
|
||||||
|
if (getType().size()==0) {
|
||||||
|
addType();
|
||||||
|
}
|
||||||
|
return getType().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value(s) for <b>type</b> (Specific type of encounter)
|
* Sets the value(s) for <b>type</b> (Specific type of encounter)
|
||||||
*
|
*
|
||||||
|
|
|
@ -126,7 +126,8 @@ public class StringDt extends BasePrimitive<String> implements IQueryParameterTy
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return super.isBaseEmpty() && StringUtils.isBlank(getValue());
|
boolean retVal = super.isBaseEmpty() && StringUtils.isBlank(getValue());
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -53,8 +53,10 @@ import org.thymeleaf.standard.expression.IStandardExpressionParser;
|
||||||
import org.thymeleaf.standard.expression.StandardExpressions;
|
import org.thymeleaf.standard.expression.StandardExpressions;
|
||||||
import org.thymeleaf.templateresolver.TemplateResolver;
|
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||||
import org.thymeleaf.util.DOMUtils;
|
import org.thymeleaf.util.DOMUtils;
|
||||||
|
import org.w3c.dom.Text;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
|
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
|
||||||
|
@ -94,6 +96,8 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.trace("Generating resource title {}", theResource);
|
||||||
|
|
||||||
String name = null;
|
String name = null;
|
||||||
if (StringUtils.isNotBlank(theProfile)) {
|
if (StringUtils.isNotBlank(theProfile)) {
|
||||||
name = myProfileToName.get(theProfile);
|
name = myProfileToName.get(theProfile);
|
||||||
|
@ -102,6 +106,8 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
name = myClassToName.get(theResource.getClass());
|
name = myClassToName.get(theResource.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.trace("Template name is {}", name);
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
if (myIgnoreMissingTemplates) {
|
if (myIgnoreMissingTemplates) {
|
||||||
ourLog.debug("No title template available for profile: {}", theProfile);
|
ourLog.debug("No title template available for profile: {}", theProfile);
|
||||||
|
@ -116,6 +122,9 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
context.setVariable("resource", theResource);
|
context.setVariable("resource", theResource);
|
||||||
|
|
||||||
String result = myTitleTemplateEngine.process(name, context);
|
String result = myTitleTemplateEngine.process(name, context);
|
||||||
|
|
||||||
|
ourLog.trace("Produced {}", result);
|
||||||
|
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
boolean inTag = false;
|
boolean inTag = false;
|
||||||
for (int i = 0; i < result.length(); i++) {
|
for (int i = 0; i < result.length(); i++) {
|
||||||
|
@ -152,6 +161,8 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
result = result.substring(0, result.lastIndexOf('<'));
|
result = result.substring(0, result.lastIndexOf('<'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = result.replace(">", ">").replace("<", "<").replace("&", "&");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (myIgnoreFailures) {
|
if (myIgnoreFailures) {
|
||||||
|
@ -214,6 +225,9 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
if (myInitialized) {
|
if (myInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.info("Initializing narrative generator");
|
||||||
|
|
||||||
myProfileToName = new HashMap<String, String>();
|
myProfileToName = new HashMap<String, String>();
|
||||||
myClassToName = new HashMap<Class<?>, String>();
|
myClassToName = new HashMap<Class<?>, String>();
|
||||||
myNameToNarrativeTemplate = new HashMap<String, String>();
|
myNameToNarrativeTemplate = new HashMap<String, String>();
|
||||||
|
@ -250,6 +264,9 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
resolver.setResourceResolver(new TitleResourceResolver());
|
resolver.setResourceResolver(new TitleResourceResolver());
|
||||||
myTitleTemplateEngine.setTemplateResolver(resolver);
|
myTitleTemplateEngine.setTemplateResolver(resolver);
|
||||||
StandardDialect dialect = new StandardDialect();
|
StandardDialect dialect = new StandardDialect();
|
||||||
|
HashSet<IProcessor> additionalProcessors = new HashSet<IProcessor>();
|
||||||
|
additionalProcessors.add(new NarrativeAttributeProcessor());
|
||||||
|
dialect.setAdditionalProcessors(additionalProcessors);
|
||||||
myTitleTemplateEngine.setDialect(dialect);
|
myTitleTemplateEngine.setDialect(dialect);
|
||||||
myTitleTemplateEngine.initialize();
|
myTitleTemplateEngine.initialize();
|
||||||
}
|
}
|
||||||
|
@ -486,7 +503,13 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
Context context = new Context();
|
Context context = new Context();
|
||||||
context.setVariable("resource", value);
|
context.setVariable("resource", value);
|
||||||
|
|
||||||
String name = myClassToName.get(value.getClass());
|
String name = null;
|
||||||
|
Class<? extends Object> nextClass = value.getClass();
|
||||||
|
do {
|
||||||
|
name = myClassToName.get(nextClass);
|
||||||
|
nextClass=nextClass.getSuperclass();
|
||||||
|
} while (name == null && nextClass.equals(Object.class)==false);
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
if (myIgnoreMissingTemplates) {
|
if (myIgnoreMissingTemplates) {
|
||||||
ourLog.debug("No narrative template available for type: {}", value.getClass());
|
ourLog.debug("No narrative template available for type: {}", value.getClass());
|
||||||
|
@ -497,10 +520,18 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
}
|
}
|
||||||
|
|
||||||
String result = myProfileTemplateEngine.process(name, context);
|
String result = myProfileTemplateEngine.process(name, context);
|
||||||
Document dom = DOMUtils.getXhtmlDOMFor(new StringReader(result));
|
String trim = result.trim();
|
||||||
|
Document dom = DOMUtils.getXhtmlDOMFor(new StringReader(trim));
|
||||||
|
|
||||||
Element firstChild = (Element) dom.getFirstChild();
|
Element firstChild = (Element) dom.getFirstChild();
|
||||||
for (Node next : firstChild.getChildren()) {
|
for (int i = 0; i < firstChild.getChildren().size(); i++) {
|
||||||
|
Node next = firstChild.getChildren().get(i);
|
||||||
|
if (i == 0 && firstChild.getChildren().size() == 1) {
|
||||||
|
if (next instanceof org.thymeleaf.dom.Text) {
|
||||||
|
org.thymeleaf.dom.Text nextText = (org.thymeleaf.dom.Text) next;
|
||||||
|
nextText.setContent(nextText.getContent().trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
theElement.addChild(next);
|
theElement.addChild(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
eventWriter.writeEnd();
|
eventWriter.writeEnd();
|
||||||
eventWriter.flush();
|
eventWriter.flush();
|
||||||
eventWriter.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName) throws IOException {
|
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName) throws IOException {
|
||||||
|
@ -507,7 +506,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||||
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null,false);
|
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null,false);
|
||||||
eventWriter.flush();
|
eventWriter.flush();
|
||||||
eventWriter.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -538,7 +536,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
eventWriter.writeEnd();
|
eventWriter.writeEnd();
|
||||||
eventWriter.flush();
|
eventWriter.flush();
|
||||||
eventWriter.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -783,9 +783,12 @@ public class RestfulServer extends HttpServlet {
|
||||||
|
|
||||||
if (theContext.getNarrativeGenerator() != null) {
|
if (theContext.getNarrativeGenerator() != null) {
|
||||||
String title = theContext.getNarrativeGenerator().generateTitle(next);
|
String title = theContext.getNarrativeGenerator().generateTitle(next);
|
||||||
|
ourLog.info("Narrative generator created title: {}", title);
|
||||||
if (StringUtils.isNotBlank(title)) {
|
if (StringUtils.isNotBlank(title)) {
|
||||||
ResourceMetadataKeyEnum.TITLE.put(next, title);
|
ResourceMetadataKeyEnum.TITLE.put(next, title);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ourLog.info("No narrative generator specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle.addResource(next, theContext, theServerBase);
|
bundle.addResource(next, theContext, theServerBase);
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<div>
|
|
||||||
<th:block th:each="prefix : ${resource.prefix}" th:text="${prefix.value} + ' '">Dr</th:block>
|
|
||||||
<th:block th:each="givenName : ${resource.given}" th:text="${givenName.value} + ' '">John</th:block>
|
|
||||||
<b th:each="familyName : ${resource.family}" th:text="${#strings.toUpperCase(familyName.value)} + ' '">SMITH</b>
|
|
||||||
<th:block th:each="suffix : ${resource.suffix}" th:text="${suffix.value} + ' '">Jr</th:block>
|
|
||||||
</div>
|
|
|
@ -16,7 +16,7 @@ a browser.
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:if="${not resource.identifierFirstRep.empty}">
|
<tr th:if="${not resource.identifierFirstRep.empty}">
|
||||||
<td>Identifier</td>
|
<td>Identifier</td>
|
||||||
<td th:text="${resource.identifierFirstRep.value.value}">8708660</td>
|
<td th:narrative="${resource.identifierFirstRep}">8708660</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr th:if="${not resource.addressFirstRep.empty}">
|
<tr th:if="${not resource.addressFirstRep.empty}">
|
||||||
<td>Address</td>
|
<td>Address</td>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div>
|
||||||
|
<th:block th:if="${not resource.empty}" th:text="${resource.value}"/>
|
||||||
|
</div>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div>
|
||||||
|
<th:block th:if="${not resource.text.empty}" th:text="${resource.text.value}"/>
|
||||||
|
<th:block th:if="${resource.text.empty}">
|
||||||
|
<th:block th:if="${!resource.codingFirstRep.empty}">
|
||||||
|
<th:block th:if="${!resource.codingFirstRep.display.empty}" th:text="${!resource.codingFirstRep.display.value}"/>
|
||||||
|
<th:block th:if="${resource.codingFirstRep.display.empty}">
|
||||||
|
<th:block th:if="${!resource.codingFirstRep.code.empty}">
|
||||||
|
<th:block th:text="${resource.codingFirstRep.code.value}"/>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
|
</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<div>
|
||||||
|
<th:block th:each="prefix : ${resource.prefix}" th:if="${!prefix.empty}" th:text="${prefix.value} + ' '">Dr</th:block>
|
||||||
|
<th:block th:each="givenName : ${resource.given}" th:if="${!givenName.empty}" th:text="${givenName.value} + ' '">John</th:block>
|
||||||
|
<b th:each="familyName : ${resource.family}" th:if="${!familyName.empty}" th:text="${#strings.toUpperCase(familyName.value)} + ' '">SMITH</b>
|
||||||
|
<th:block th:each="suffix : ${resource.suffix}" th:if="${!suffix.empty}" th:text="${suffix.value} + ' '">Jr</th:block>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div>
|
||||||
|
<th:block th:if="${!resource.label.empty}" th:text="${resource.label.value}"/>
|
||||||
|
<th:block th:if="${resource.label.empty}" th:text="${resource.value.valueAsString}"/>
|
||||||
|
</div>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div>
|
||||||
|
<th:block th:if="${!resource.start.empty} and ${!resource.end.empty}" th:text="${resource.start.value} + ' - ' + ${resource.end.value}"/>
|
||||||
|
<th:block th:if="${!resource.start.empty} and ${resource.end.empty}" th:text="${resource.start.value} + ' - ?'"/>
|
||||||
|
<th:block th:if="${resource.start.empty} and ${!resource.end.empty}" th:text="'? - ' + ${resource.end.value}"/>
|
||||||
|
</div>
|
|
@ -3,38 +3,53 @@
|
||||||
# Primitive Datatypes
|
# Primitive Datatypes
|
||||||
################################################
|
################################################
|
||||||
|
|
||||||
string.class=ca.uhn.fhir.model.primitive.StringDt
|
code.class=ca.uhn.fhir.model.primitive.CodeDt
|
||||||
string.narrative=classpath:ca/uhn/fhir/narrative/StringDt.html
|
code.narrative=classpath:ca/uhn/fhir/narrative/datatype/CodeDt.html
|
||||||
|
|
||||||
datetime.class=ca.uhn.fhir.model.primitive.DateTimeDt
|
datetime.class=ca.uhn.fhir.model.primitive.DateTimeDt
|
||||||
datetime.narrative=classpath:ca/uhn/fhir/narrative/DateTimeDt.html
|
datetime.narrative=classpath:ca/uhn/fhir/narrative/datatype/DateTimeDt.html
|
||||||
|
|
||||||
# Instant uses DateTime narrative
|
# Instant uses DateTime narrative
|
||||||
instant.class=ca.uhn.fhir.model.primitive.InstantDt
|
instant.class=ca.uhn.fhir.model.primitive.InstantDt
|
||||||
instant.narrative=classpath:ca/uhn/fhir/narrative/DateTimeDt.html
|
instant.narrative=classpath:ca/uhn/fhir/narrative/datatype/DateTimeDt.html
|
||||||
|
|
||||||
|
string.class=ca.uhn.fhir.model.primitive.StringDt
|
||||||
|
string.narrative=classpath:ca/uhn/fhir/narrative/datatype/StringDt.html
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
# Composite Datatypes
|
# Composite Datatypes
|
||||||
################################################
|
################################################
|
||||||
|
|
||||||
address.class=ca.uhn.fhir.model.dstu.composite.AddressDt
|
address.class=ca.uhn.fhir.model.dstu.composite.AddressDt
|
||||||
address.narrative=classpath:ca/uhn/fhir/narrative/AddressDt.html
|
address.narrative=classpath:ca/uhn/fhir/narrative/datatype/AddressDt.html
|
||||||
|
|
||||||
|
codeableconcept.class=ca.uhn.fhir.model.dstu.composite.CodeableConceptDt
|
||||||
|
codeableconcept.narrative=classpath:ca/uhn/fhir/narrative/datatype/CodeableConceptDt.html
|
||||||
|
|
||||||
humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt
|
humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt
|
||||||
humanname.narrative=classpath:ca/uhn/fhir/narrative/HumanNameDt.html
|
humanname.narrative=classpath:ca/uhn/fhir/narrative/datatype/HumanNameDt.html
|
||||||
|
|
||||||
|
identifier.class=ca.uhn.fhir.model.dstu.composite.IdentifierDt
|
||||||
|
identifier.narrative=classpath:ca/uhn/fhir/narrative/datatype/IdentifierDt.html
|
||||||
|
|
||||||
|
period.class=ca.uhn.fhir.model.dstu.composite.PeriodDt
|
||||||
|
period.narrative=classpath:ca/uhn/fhir/narrative/datatype/PeriodDt.html
|
||||||
|
|
||||||
quantity.class=ca.uhn.fhir.model.dstu.composite.QuantityDt
|
quantity.class=ca.uhn.fhir.model.dstu.composite.QuantityDt
|
||||||
quantity.narrative=classpath:ca/uhn/fhir/narrative/QuantityDt.html
|
quantity.narrative=classpath:ca/uhn/fhir/narrative/datatype/QuantityDt.html
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
# Resources
|
# Resources
|
||||||
################################################
|
################################################
|
||||||
|
|
||||||
|
diagnosticreport.class=ca.uhn.fhir.model.dstu.resource.DiagnosticReport
|
||||||
|
diagnosticreport.narrative=classpath:ca/uhn/fhir/narrative/DiagnosticReport.html
|
||||||
|
diagnosticreport.title=classpath:ca/uhn/fhir/narrative/title/DiagnosticReport.html
|
||||||
|
|
||||||
|
encounter.class=ca.uhn.fhir.model.dstu.resource.Encounter
|
||||||
|
encounter.title=classpath:ca/uhn/fhir/narrative/title/Encounter.html
|
||||||
|
|
||||||
patient.class=ca.uhn.fhir.model.dstu.resource.Patient
|
patient.class=ca.uhn.fhir.model.dstu.resource.Patient
|
||||||
patient.narrative=classpath:ca/uhn/fhir/narrative/Patient.html
|
patient.narrative=classpath:ca/uhn/fhir/narrative/Patient.html
|
||||||
patient.title=classpath:ca/uhn/fhir/narrative/title/Patient.html
|
patient.title=classpath:ca/uhn/fhir/narrative/title/Patient.html
|
||||||
|
|
||||||
|
|
||||||
diagnosticreport.class=ca.uhn.fhir.model.dstu.resource.DiagnosticReport
|
|
||||||
diagnosticreport.narrative=classpath:ca/uhn/fhir/narrative/DiagnosticReport.html
|
|
||||||
diagnosticreport.title=classpath:ca/uhn/fhir/narrative/title/DiagnosticReport.html
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<div>
|
||||||
|
<th:block th:if="${!resource.identifierFirstRep.empty}" th:narrative="${resource.identifierFirstRep}" />
|
||||||
|
<th:block th:if="${not resource.status.empty}">
|
||||||
|
/ <th:block th:narrative="${resource.status}"/>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:if="${not resource.typeFirstRep.empty}">
|
||||||
|
/ <th:block th:narrative="${resource.typeFirstRep}"/>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:if="${not resource.classElement.empty}">
|
||||||
|
/ <th:block th:narrative="${resource.classElement}"/>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:if="${not resource.period.empty}">
|
||||||
|
/ <th:block th:narrative="${resource.period}"/>
|
||||||
|
</th:block>
|
||||||
|
</div>
|
|
@ -1,9 +1,6 @@
|
||||||
<div>
|
<div>
|
||||||
<th:block th:each="prefix : ${resource.nameFirstRep.prefix}" th:text="${prefix.value} + ' '">Dr</th:block>
|
<th:block th:narrative="${resource.nameFirstRep}" />
|
||||||
<th:block th:each="givenName : ${resource.nameFirstRep.given}" th:text="${givenName.value} + ' '">John</th:block>
|
|
||||||
<th:block th:each="familyName : ${resource.nameFirstRep.family}" th:text="${#strings.toUpperCase(familyName.value)} + ' '">SMITH</th:block>
|
|
||||||
<th:block th:each="suffix : ${resource.nameFirstRep.suffix}" th:text="${suffix.value} + ' '">Jr</th:block>
|
|
||||||
<th:block th:if="${not resource.identifierFirstRep.empty}">
|
<th:block th:if="${not resource.identifierFirstRep.empty}">
|
||||||
(<th:block th:text="${resource.identifierFirstRep.value.value}">8708660</th:block>)
|
(<th:block th:narrative="${resource.identifierFirstRep}">8708660</th:block>)
|
||||||
</th:block>
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,20 +10,27 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
|
import ca.uhn.fhir.model.dstu.composite.PeriodDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
|
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Encounter;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.DiagnosticReportStatusEnum;
|
import ca.uhn.fhir.model.dstu.valueset.DiagnosticReportStatusEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.EncounterClassEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.EncounterTypeEnum;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.ObservationStatusEnum;
|
import ca.uhn.fhir.model.dstu.valueset.ObservationStatusEnum;
|
||||||
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
|
||||||
public class DefaultThymeleafNarrativeGeneratorTest {
|
public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
|
private FhirContext myCtx;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultThymeleafNarrativeGeneratorTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultThymeleafNarrativeGeneratorTest.class);
|
||||||
private DefaultThymeleafNarrativeGenerator gen;
|
private DefaultThymeleafNarrativeGenerator gen;
|
||||||
|
|
||||||
|
@ -33,14 +40,20 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
gen.setUseHapiServerConformanceNarrative(true);
|
gen.setUseHapiServerConformanceNarrative(true);
|
||||||
gen.setIgnoreFailures(false);
|
gen.setIgnoreFailures(false);
|
||||||
gen.setIgnoreMissingTemplates(false);
|
gen.setIgnoreMissingTemplates(false);
|
||||||
|
|
||||||
|
myCtx=new FhirContext();
|
||||||
|
myCtx.setNarrativeGenerator(gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGeneratePatient() throws DataFormatException {
|
public void testGeneratePatient() throws DataFormatException {
|
||||||
Patient value = new Patient();
|
Patient value = new Patient();
|
||||||
|
|
||||||
value.addIdentifier().setSystem("urn:names").setValue("123456");
|
value.addIdentifier().setSystem("urn:names").setValue("123456");
|
||||||
value.addName().addFamily("blow").addGiven("joe").addGiven("john");
|
value.addName().addFamily("blow").addGiven("joe").addGiven(null).addGiven("john");
|
||||||
value.getAddressFirstRep().addLine("123 Fake Street").addLine("Unit 1");
|
value.getAddressFirstRep().addLine("123 Fake Street").addLine("Unit 1");
|
||||||
value.getAddressFirstRep().setCity("Toronto").setState("ON").setCountry("Canada");
|
value.getAddressFirstRep().setCity("Toronto").setState("ON").setCountry("Canada");
|
||||||
|
|
||||||
|
@ -52,11 +65,33 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
String title = gen.generateTitle(value);
|
String title = gen.generateTitle(value);
|
||||||
assertEquals("joe john BLOW (123456)", title);
|
assertEquals("joe john BLOW (123456)", title);
|
||||||
ourLog.info(title);
|
ourLog.info(title);
|
||||||
|
|
||||||
|
value.getIdentifierFirstRep().setLabel("FOO MRN 123");
|
||||||
|
title = gen.generateTitle(value);
|
||||||
|
assertEquals("joe john BLOW (FOO MRN 123)", title);
|
||||||
|
ourLog.info(title);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGenerateEncounter() throws DataFormatException {
|
||||||
|
Encounter enc = new Encounter();
|
||||||
|
|
||||||
|
enc.addIdentifier("urn:visits", "1234567");
|
||||||
|
enc.setClassElement(EncounterClassEnum.AMBULATORY);
|
||||||
|
enc.setPeriod(new PeriodDt().setStart(new DateTimeDt("2001-01-02T11:11:00")));
|
||||||
|
enc.setType(EncounterTypeEnum.ANNUAL_DIABETES_MELLITUS_SCREENING);
|
||||||
|
|
||||||
|
String title = gen.generateTitle(enc);
|
||||||
|
assertEquals("1234567 / ADMS / ambulatory / Tue Jan 02 11:11:00 EST 2001 - ?", title);
|
||||||
|
ourLog.info(title);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateServerConformance() throws DataFormatException {
|
public void testGenerateServerConformance() throws DataFormatException {
|
||||||
Conformance value = new FhirContext().newXmlParser().parseResource(Conformance.class, new InputStreamReader(getClass().getResourceAsStream("/server-conformance-statement.xml")));
|
Conformance value = myCtx.newXmlParser().parseResource(Conformance.class, new InputStreamReader(getClass().getResourceAsStream("/server-conformance-statement.xml")));
|
||||||
|
|
||||||
String output = gen.generateNarrative(value).getDiv().getValueAsString();
|
String output = gen.generateNarrative(value).getDiv().getValueAsString();
|
||||||
|
|
||||||
|
@ -76,6 +111,7 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
String output = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value).getDiv().getValueAsString();
|
String output = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value).getDiv().getValueAsString();
|
||||||
|
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
|
assertThat(output,StringContains.containsString(value.getName().getText().getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -85,7 +121,7 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
value.getIssued().setValueAsString("2011-02-22T11:13:00");
|
value.getIssued().setValueAsString("2011-02-22T11:13:00");
|
||||||
value.setStatus(DiagnosticReportStatusEnum.FINAL);
|
value.setStatus(DiagnosticReportStatusEnum.FINAL);
|
||||||
|
|
||||||
value.getName().setText("Some Diagnostic Report");
|
value.getName().setText("Some & Diagnostic Report");
|
||||||
{
|
{
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
obs.getName().addCoding().setCode("1938HB").setDisplay("Hemoglobin");
|
obs.getName().addCoding().setCode("1938HB").setDisplay("Hemoglobin");
|
||||||
|
@ -106,7 +142,7 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
String output = generateNarrative.getDiv().getValueAsString();
|
String output = generateNarrative.getDiv().getValueAsString();
|
||||||
|
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\"> Some Diagnostic Report </div>"));
|
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\"> Some & Diagnostic Report </div>"));
|
||||||
|
|
||||||
String title = gen.generateTitle(value);
|
String title = gen.generateTitle(value);
|
||||||
ourLog.info(title);
|
ourLog.info(title);
|
||||||
|
@ -115,11 +151,9 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
|
|
||||||
// Now try it with the parser
|
// Now try it with the parser
|
||||||
|
|
||||||
FhirContext context = new FhirContext();
|
output = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(value);
|
||||||
context.setNarrativeGenerator(gen);
|
|
||||||
output = context.newXmlParser().setPrettyPrint(true).encodeResourceToString(value);
|
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\"> Some Diagnostic Report </div>"));
|
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\"> Some & Diagnostic Report </div>"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,24 @@
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<root>
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<appender-ref ref="STDOUT" />
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
<file>${fhir.logdir}/logFile.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${fhir.logdir}/logFile.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
|
||||||
|
<encoder>
|
||||||
|
<!-- [%file:%line] -->
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
|
@ -16,7 +16,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br /> <label class="navBarButtonLabel">Pretty</label>
|
<br /> <label class="navBarButtonLabel">Pretty</label>
|
||||||
<div class="btn-group top-buffer" data-toggle="buttons">
|
<div class="btn-group top-buffer" data-toggle="buttons" id="prettyBtnGroup">
|
||||||
<label class="btn btn-sm btn-default active"> <input
|
<label class="btn btn-sm btn-default active"> <input
|
||||||
type="radio" name="pretty" id="pretty-default" value="" />(default)
|
type="radio" name="pretty" id="pretty-default" value="" />(default)
|
||||||
</label> <label class="btn btn-sm btn-default"> <input
|
</label> <label class="btn btn-sm btn-default"> <input
|
||||||
|
@ -28,6 +28,11 @@
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$( document ).ready(function() {
|
$( document ).ready(function() {
|
||||||
|
|
||||||
|
// Encoding buttons are wider, so set the shorter group to the same width
|
||||||
|
// so that they wrap at the same time if the page is narrow
|
||||||
|
$('#prettyBtnGroup').width($('#encodingBtnGroup').width());
|
||||||
|
|
||||||
<th:block th:switch="${encoding}">
|
<th:block th:switch="${encoding}">
|
||||||
<th:block th:case="'xml'">
|
<th:block th:case="'xml'">
|
||||||
$('#encode-xml').trigger("click");
|
$('#encode-xml').trigger("click");
|
||||||
|
|
|
@ -151,6 +151,22 @@
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the first repetition for <b>${child.elementName}</b> (${child.shortName}),
|
||||||
|
* creating it if it does not already exist.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>Definition:</b>
|
||||||
|
* ${child.definition}
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public ${child.boundDatatype}<${child.bindingClass}> get${child.methodName}FirstRep() {
|
||||||
|
if (get${child.methodName}().size() == 0) {
|
||||||
|
add${child.methodName}();
|
||||||
|
}
|
||||||
|
return get${child.methodName}().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a value for <b>${child.elementName}</b> (${child.shortName})
|
* Add a value for <b>${child.elementName}</b> (${child.shortName})
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue