Narrative generation continuing
This commit is contained in:
parent
21619e5e46
commit
de50244875
|
@ -46,12 +46,12 @@
|
||||||
|
|
||||||
<!-- <dependency> <groupId>org.codehaus.woodstox</groupId> <artifactId>stax2-api</artifactId> <version>3.1.3</version> </dependency> -->
|
<!-- <dependency> <groupId>org.codehaus.woodstox</groupId> <artifactId>stax2-api</artifactId> <version>3.1.3</version> </dependency> -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.thymeleaf</groupId>
|
<groupId>org.thymeleaf</groupId>
|
||||||
<artifactId>thymeleaf</artifactId>
|
<artifactId>thymeleaf</artifactId>
|
||||||
<version>2.1.2.RELEASE</version>
|
<version>2.1.2.RELEASE</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- General -->
|
<!-- General -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -8,4 +8,9 @@ public abstract class BasePrimitive<T> extends BaseElement implements IPrimitive
|
||||||
return super.isBaseEmpty() && getValue() == null;
|
return super.isBaseEmpty() && getValue() == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "[" + getValueAsString() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,30 +41,15 @@ import ca.uhn.fhir.parser.DataFormatException;
|
||||||
public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ThymeleafNarrativeGenerator.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ThymeleafNarrativeGenerator.class);
|
||||||
|
|
||||||
private HashMap<String, String> myProfileToNarrativeTemplate;
|
|
||||||
private TemplateEngine myProfileTemplateEngine;
|
|
||||||
|
|
||||||
private HashMap<String, String> myDatatypeClassNameToNarrativeTemplate;
|
private HashMap<String, String> myDatatypeClassNameToNarrativeTemplate;
|
||||||
|
|
||||||
private TemplateEngine myDatatypeTemplateEngine;
|
private TemplateEngine myDatatypeTemplateEngine;
|
||||||
|
|
||||||
private boolean myIgnoreFailures = true;
|
private boolean myIgnoreFailures = true;
|
||||||
|
|
||||||
/**
|
private boolean myIgnoreMissingTemplates = true;
|
||||||
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative
|
|
||||||
* indicating that no narrative is available.
|
|
||||||
*/
|
|
||||||
public boolean isIgnoreFailures() {
|
|
||||||
return myIgnoreFailures;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private TemplateEngine myProfileTemplateEngine;
|
||||||
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative
|
private HashMap<String, String> myProfileToNarrativeTemplate;
|
||||||
* indicating that no narrative is available.
|
|
||||||
*/
|
|
||||||
public void setIgnoreFailures(boolean theIgnoreFailures) {
|
|
||||||
myIgnoreFailures = theIgnoreFailures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ThymeleafNarrativeGenerator() throws IOException {
|
public ThymeleafNarrativeGenerator() throws IOException {
|
||||||
myProfileToNarrativeTemplate = new HashMap<String, String>();
|
myProfileToNarrativeTemplate = new HashMap<String, String>();
|
||||||
|
@ -96,6 +81,48 @@ public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NarrativeDt generateNarrative(String theProfile, IResource theResource) {
|
||||||
|
if (myIgnoreMissingTemplates && !myProfileToNarrativeTemplate.containsKey(theProfile)) {
|
||||||
|
ourLog.debug("No narrative template available for profile: {}", theProfile);
|
||||||
|
return new NarrativeDt(new XhtmlDt("<div>No narrative available</div>"), NarrativeStatusEnum.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Context context = new Context();
|
||||||
|
context.setVariable("resource", theResource);
|
||||||
|
|
||||||
|
String result = myProfileTemplateEngine.process(theProfile, context);
|
||||||
|
result = result.replaceAll("\\s+", " ").replace("> ", ">").replace(" <", "<");
|
||||||
|
|
||||||
|
XhtmlDt div = new XhtmlDt(result);
|
||||||
|
return new NarrativeDt(div, NarrativeStatusEnum.GENERATED);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (myIgnoreFailures) {
|
||||||
|
ourLog.error("Failed to generate narrative", e);
|
||||||
|
return new NarrativeDt(new XhtmlDt("<div>No narrative available</div>"), NarrativeStatusEnum.EMPTY);
|
||||||
|
} else {
|
||||||
|
throw new DataFormatException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative
|
||||||
|
* indicating that no narrative is available.
|
||||||
|
*/
|
||||||
|
public boolean isIgnoreFailures() {
|
||||||
|
return myIgnoreFailures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, will return an empty narrative block for any
|
||||||
|
* profiles where no template is available
|
||||||
|
*/
|
||||||
|
public boolean isIgnoreMissingTemplates() {
|
||||||
|
return myIgnoreMissingTemplates;
|
||||||
|
}
|
||||||
|
|
||||||
private void loadProperties(String propFileName) throws IOException {
|
private void loadProperties(String propFileName) throws IOException {
|
||||||
Properties file = new Properties();
|
Properties file = new Properties();
|
||||||
|
|
||||||
|
@ -144,37 +171,6 @@ public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public NarrativeDt generateNarrative(String theProfile, IResource theResource) {
|
|
||||||
try {
|
|
||||||
Context context = new Context();
|
|
||||||
context.setVariable("resource", theResource);
|
|
||||||
|
|
||||||
String result = myProfileTemplateEngine.process(theProfile, context);
|
|
||||||
result = result.replaceAll("\\s+", " ").replace("> ", ">").replace(" <", "<");
|
|
||||||
|
|
||||||
return new NarrativeDt(new XhtmlDt(result), NarrativeStatusEnum.GENERATED);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (myIgnoreFailures) {
|
|
||||||
ourLog.error("Failed to generate narrative", e);
|
|
||||||
return new NarrativeDt(new XhtmlDt("<div>Error: no narrative available</div>"), NarrativeStatusEnum.EMPTY);
|
|
||||||
} else {
|
|
||||||
throw new DataFormatException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// public String generateString(Patient theValue) {
|
|
||||||
//
|
|
||||||
// Context context = new Context();
|
|
||||||
// context.setVariable("resource", theValue);
|
|
||||||
// String result = myProfileTemplateEngine.process("ca/uhn/fhir/narrative/Patient.html", context);
|
|
||||||
//
|
|
||||||
// ourLog.info("Result: {}", result);
|
|
||||||
//
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private InputStream loadResource(String name) {
|
private InputStream loadResource(String name) {
|
||||||
if (name.startsWith("classpath:")) {
|
if (name.startsWith("classpath:")) {
|
||||||
String cpName = name.substring("classpath:".length());
|
String cpName = name.substring("classpath:".length());
|
||||||
|
@ -191,17 +187,31 @@ public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ProfileResourceResolver implements IResourceResolver {
|
/**
|
||||||
@Override
|
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative
|
||||||
public String getName() {
|
* indicating that no narrative is available.
|
||||||
return getClass().getCanonicalName();
|
*/
|
||||||
|
public void setIgnoreFailures(boolean theIgnoreFailures) {
|
||||||
|
myIgnoreFailures = theIgnoreFailures;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// public String generateString(Patient theValue) {
|
||||||
public InputStream getResourceAsStream(TemplateProcessingParameters theTemplateProcessingParameters, String theResourceName) {
|
//
|
||||||
String template = myProfileToNarrativeTemplate.get(theResourceName);
|
// Context context = new Context();
|
||||||
return new ReaderInputStream(new StringReader(template));
|
// context.setVariable("resource", theValue);
|
||||||
}
|
// String result = myProfileTemplateEngine.process("ca/uhn/fhir/narrative/Patient.html", context);
|
||||||
|
//
|
||||||
|
// ourLog.info("Result: {}", result);
|
||||||
|
//
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, will return an empty narrative block for any
|
||||||
|
* profiles where no template is available
|
||||||
|
*/
|
||||||
|
public void setIgnoreMissingTemplates(boolean theIgnoreMissingTemplates) {
|
||||||
|
myIgnoreMissingTemplates = theIgnoreMissingTemplates;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class DatatypeResourceResolver implements IResourceResolver {
|
private final class DatatypeResourceResolver implements IResourceResolver {
|
||||||
|
@ -223,6 +233,11 @@ public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
||||||
super("narrative");
|
super("narrative");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPrecedence() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ProcessorResult processAttribute(Arguments theArguments, Element theElement, String theAttributeName) {
|
protected ProcessorResult processAttribute(Arguments theArguments, Element theElement, String theAttributeName) {
|
||||||
final String attributeValue = theElement.getAttributeValue(theAttributeName);
|
final String attributeValue = theElement.getAttributeValue(theAttributeName);
|
||||||
|
@ -251,11 +266,23 @@ public class ThymeleafNarrativeGenerator implements INarrativeGenerator {
|
||||||
return ProcessorResult.ok();
|
return ProcessorResult.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPrecedence() {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class ProfileResourceResolver implements IResourceResolver {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return getClass().getCanonicalName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getResourceAsStream(TemplateProcessingParameters theTemplateProcessingParameters, String theResourceName) {
|
||||||
|
String template = myProfileToNarrativeTemplate.get(theResourceName);
|
||||||
|
if (template == null) {
|
||||||
|
ourLog.info("No narative template for resource profile: {}", theResourceName);
|
||||||
|
return new ReaderInputStream(new StringReader(""));
|
||||||
|
}
|
||||||
|
return new ReaderInputStream(new StringReader(template));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,14 @@ import javax.json.stream.JsonGenerator;
|
||||||
import javax.json.stream.JsonGeneratorFactory;
|
import javax.json.stream.JsonGeneratorFactory;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition;
|
import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition;
|
||||||
|
import ca.uhn.fhir.context.RuntimeChildNarrativeDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
|
import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.model.api.BaseBundle;
|
import ca.uhn.fhir.model.api.BaseBundle;
|
||||||
|
@ -48,6 +50,7 @@ import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
|
||||||
import ca.uhn.fhir.model.api.UndeclaredExtension;
|
import ca.uhn.fhir.model.api.UndeclaredExtension;
|
||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||||
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||||
import ca.uhn.fhir.model.primitive.BooleanDt;
|
import ca.uhn.fhir.model.primitive.BooleanDt;
|
||||||
import ca.uhn.fhir.model.primitive.DecimalDt;
|
import ca.uhn.fhir.model.primitive.DecimalDt;
|
||||||
|
@ -55,6 +58,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||||
|
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||||
|
|
||||||
public class JsonParser extends BaseParser implements IParser {
|
public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
|
@ -118,7 +122,8 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
writeAuthor(nextEntry, eventWriter);
|
writeAuthor(nextEntry, eventWriter);
|
||||||
|
|
||||||
IResource resource = nextEntry.getResource();
|
IResource resource = nextEntry.getResource();
|
||||||
encodeResourceToJsonStreamWriter(resource, eventWriter, "content");
|
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(resource);
|
||||||
|
encodeResourceToJsonStreamWriter(resDef, resource, eventWriter, "content");
|
||||||
|
|
||||||
eventWriter.writeEnd(); // entry object
|
eventWriter.writeEnd(); // entry object
|
||||||
}
|
}
|
||||||
|
@ -137,9 +142,12 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encodeResourceToWriter(IResource theResource, Writer theWriter) throws IOException {
|
public void encodeResourceToWriter(IResource theResource, Writer theWriter) throws IOException {
|
||||||
|
Validate.notNull(theResource, "Resource can not be null");
|
||||||
|
|
||||||
JsonGenerator eventWriter = createJsonGenerator(theWriter);
|
JsonGenerator eventWriter = createJsonGenerator(theWriter);
|
||||||
|
|
||||||
encodeResourceToJsonStreamWriter(theResource, eventWriter, null);
|
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||||
|
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null);
|
||||||
eventWriter.flush();
|
eventWriter.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +439,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
return eventWriter;
|
return eventWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeChildElementToStreamWriter(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 {
|
||||||
|
|
||||||
switch (theChildDef.getChildType()) {
|
switch (theChildDef.getChildType()) {
|
||||||
case PRIMITIVE_DATATYPE: {
|
case PRIMITIVE_DATATYPE: {
|
||||||
|
@ -470,10 +478,9 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
if (theChildName != null) {
|
if (theChildName != null) {
|
||||||
theWriter.writeStartObject(theChildName);
|
theWriter.writeStartObject(theChildName);
|
||||||
} else {
|
} else {
|
||||||
theWriter.flush();// TODO: remove
|
|
||||||
theWriter.writeStartObject();
|
theWriter.writeStartObject();
|
||||||
}
|
}
|
||||||
encodeCompositeElementToStreamWriter(theValue, theWriter, childCompositeDef);
|
encodeCompositeElementToStreamWriter(theResDef, theResource, theValue, theWriter, childCompositeDef);
|
||||||
theWriter.writeEnd();
|
theWriter.writeEnd();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -505,7 +512,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
theWriter.writeStartArray(theChildName);
|
theWriter.writeStartArray(theChildName);
|
||||||
ContainedDt value = (ContainedDt) theValue;
|
ContainedDt value = (ContainedDt) theValue;
|
||||||
for (IResource next : value.getContainedResources()) {
|
for (IResource next : value.getContainedResources()) {
|
||||||
encodeResourceToJsonStreamWriter(next, theWriter, null);
|
encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null);
|
||||||
}
|
}
|
||||||
theWriter.writeEnd();
|
theWriter.writeEnd();
|
||||||
break;
|
break;
|
||||||
|
@ -526,8 +533,22 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeCompositeElementChildrenToStreamWriter(IElement theElement, JsonGenerator theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren) throws IOException {
|
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren) throws IOException {
|
||||||
for (BaseRuntimeChildDefinition nextChild : theChildren) {
|
for (BaseRuntimeChildDefinition nextChild : theChildren) {
|
||||||
|
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
|
||||||
|
INarrativeGenerator gen = myContext.getNarrativeGenerator();
|
||||||
|
if (gen != null) {
|
||||||
|
NarrativeDt narr = gen.generateNarrative(theResDef.getResourceProfile(), theResource);
|
||||||
|
if (narr!=null) {
|
||||||
|
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||||
|
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
|
||||||
|
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
|
||||||
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<? extends IElement> values = nextChild.getAccessor().getValues(theElement);
|
List<? extends IElement> values = nextChild.getAccessor().getValues(theElement);
|
||||||
if (values == null || values.isEmpty()) {
|
if (values == null || values.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -565,7 +586,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
String extensionUrl = nextChild.getExtensionUrl();
|
String extensionUrl = nextChild.getExtensionUrl();
|
||||||
theEventWriter.write("url", extensionUrl);
|
theEventWriter.write("url", extensionUrl);
|
||||||
// theEventWriter.writeName(childName);
|
// theEventWriter.writeName(childName);
|
||||||
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, childName);
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName);
|
||||||
|
|
||||||
theEventWriter.writeEnd();
|
theEventWriter.writeEnd();
|
||||||
|
|
||||||
|
@ -578,14 +599,13 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
|
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
|
||||||
theEventWriter.writeStartArray(childName);
|
theEventWriter.writeStartArray(childName);
|
||||||
inArray = true;
|
inArray = true;
|
||||||
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, null);
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null);
|
||||||
} else {
|
} else {
|
||||||
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, childName);
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName);
|
||||||
}
|
}
|
||||||
currentChildName = childName;
|
currentChildName = childName;
|
||||||
} else {
|
} else {
|
||||||
theEventWriter.flush();// TODO: remove
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null);
|
||||||
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextValue instanceof ISupportsUndeclaredExtensions) {
|
if (nextValue instanceof ISupportsUndeclaredExtensions) {
|
||||||
|
@ -615,7 +635,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
theEventWriter.writeStartObject();
|
theEventWriter.writeStartObject();
|
||||||
theEventWriter.writeStartArray("extension");
|
theEventWriter.writeStartArray("extension");
|
||||||
for (HeldExtension nextExt : extensions.get(i)) {
|
for (HeldExtension nextExt : extensions.get(i)) {
|
||||||
nextExt.write(theEventWriter);
|
nextExt.write(theResDef, theResource, theEventWriter);
|
||||||
}
|
}
|
||||||
theEventWriter.writeEnd();
|
theEventWriter.writeEnd();
|
||||||
theEventWriter.writeEnd();
|
theEventWriter.writeEnd();
|
||||||
|
@ -623,7 +643,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
if (!haveContent) {
|
if (!haveContent) {
|
||||||
// theEventWriter.writeEnd();
|
// theEventWriter.writeEnd();
|
||||||
theEventWriter.flush(); // TODO: remove
|
|
||||||
theEventWriter.writeNull();
|
theEventWriter.writeNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -648,27 +667,26 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
theEventWriter.writeEnd();
|
theEventWriter.writeEnd();
|
||||||
theEventWriter.flush(); // TODO: remove
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeCompositeElementToStreamWriter(IElement theElement, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws IOException, DataFormatException {
|
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws IOException, DataFormatException {
|
||||||
encodeExtensionsIfPresent(theEventWriter, theElement);
|
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement);
|
||||||
encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getExtensions());
|
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions());
|
||||||
encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getChildren());
|
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeExtensionsIfPresent(JsonGenerator theWriter, IElement theResource) throws IOException {
|
private void encodeExtensionsIfPresent(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theElement) throws IOException {
|
||||||
if (theResource instanceof ISupportsUndeclaredExtensions) {
|
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||||
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theResource;
|
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
|
||||||
encodeUndeclaredExtensions(theWriter, res.getUndeclaredExtensions(), "extension");
|
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredExtensions(), "extension");
|
||||||
encodeUndeclaredExtensions(theWriter, res.getUndeclaredModifierExtensions(), "modifierExtension");
|
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredModifierExtensions(), "modifierExtension");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeResourceToJsonStreamWriter(IResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull) throws IOException {
|
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull) throws IOException {
|
||||||
super.containResourcesForEncoding(theResource);
|
super.containResourcesForEncoding(theResource);
|
||||||
|
|
||||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||||
|
@ -684,12 +702,12 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
theEventWriter.write("id", theResource.getId().getValue());
|
theEventWriter.write("id", theResource.getId().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeCompositeElementToStreamWriter(theResource, theEventWriter, resDef);
|
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef);
|
||||||
|
|
||||||
theEventWriter.writeEnd();
|
theEventWriter.writeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeUndeclaredExtensions(JsonGenerator theWriter, List<UndeclaredExtension> extensions, String theTagName) throws IOException {
|
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, List<UndeclaredExtension> extensions, String theTagName) throws IOException {
|
||||||
if (extensions.isEmpty()) {
|
if (extensions.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -707,11 +725,11 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
|
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
|
||||||
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass());
|
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass());
|
||||||
// theWriter.writeName("value" + childDef.getName());
|
// theWriter.writeName("value" + childDef.getName());
|
||||||
encodeChildElementToStreamWriter(theWriter, nextValue, childDef, "value" + childDef.getName());
|
encodeChildElementToStreamWriter(theResDef, theResource, theWriter, nextValue, childDef, "value" + childDef.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeUndeclaredExtensions(theWriter, next.getUndeclaredExtensions(), "extension");
|
encodeUndeclaredExtensions(theResDef, theResource, theWriter, next.getUndeclaredExtensions(), "extension");
|
||||||
encodeUndeclaredExtensions(theWriter, next.getUndeclaredModifierExtensions(), "modifierExtension");
|
encodeUndeclaredExtensions(theResDef, theResource, theWriter, next.getUndeclaredModifierExtensions(), "modifierExtension");
|
||||||
|
|
||||||
theWriter.writeEnd();
|
theWriter.writeEnd();
|
||||||
}
|
}
|
||||||
|
@ -762,13 +780,13 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
myUndeclaredExtension = theUndeclaredExtension;
|
myUndeclaredExtension = theUndeclaredExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(JsonGenerator theEventWriter) throws IOException {
|
public void write(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter) throws IOException {
|
||||||
if (myUndeclaredExtension != null) {
|
if (myUndeclaredExtension != null) {
|
||||||
writeUndeclaredExt(theEventWriter, myUndeclaredExtension);
|
writeUndeclaredExt(theResDef, theResource, theEventWriter, myUndeclaredExtension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeUndeclaredExt(JsonGenerator theEventWriter, UndeclaredExtension ext) throws IOException {
|
private void writeUndeclaredExt(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, UndeclaredExtension ext) throws IOException {
|
||||||
theEventWriter.writeStartObject();
|
theEventWriter.writeStartObject();
|
||||||
theEventWriter.write("url", ext.getUrl());
|
theEventWriter.write("url", ext.getUrl());
|
||||||
|
|
||||||
|
@ -778,13 +796,13 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
} else if (value == null) {
|
} else if (value == null) {
|
||||||
theEventWriter.writeStartArray("extension");
|
theEventWriter.writeStartArray("extension");
|
||||||
for (UndeclaredExtension next : ext.getUndeclaredExtensions()) {
|
for (UndeclaredExtension next : ext.getUndeclaredExtensions()) {
|
||||||
writeUndeclaredExt(theEventWriter, next);
|
writeUndeclaredExt(theResDef, theResource, theEventWriter, next);
|
||||||
}
|
}
|
||||||
theEventWriter.writeEnd();
|
theEventWriter.writeEnd();
|
||||||
} else {
|
} else {
|
||||||
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition(value.getClass());
|
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition(value.getClass());
|
||||||
// theEventWriter.writeName("value" + def.getName());
|
// theEventWriter.writeName("value" + def.getName());
|
||||||
encodeChildElementToStreamWriter(theEventWriter, value, def, "value" + def.getName());
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, def, "value" + def.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// theEventWriter.name(myUndeclaredExtension.get);
|
// theEventWriter.name(myUndeclaredExtension.get);
|
||||||
|
|
|
@ -519,7 +519,11 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
if (firstEvent) {
|
if (firstEvent) {
|
||||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||||
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
||||||
theEventWriter.writeDefaultNamespace(se.getName().getNamespaceURI());
|
String namespaceURI = se.getName().getNamespaceURI();
|
||||||
|
if (StringUtils.isBlank(namespaceURI)) {
|
||||||
|
namespaceURI = "http://www.w3.org/1999/xhtml";
|
||||||
|
}
|
||||||
|
theEventWriter.writeDefaultNamespace(namespaceURI);
|
||||||
} else {
|
} else {
|
||||||
theEventWriter.writeNamespace(se.getName().getPrefix(), se.getName().getNamespaceURI());
|
theEventWriter.writeNamespace(se.getName().getPrefix(), se.getName().getNamespaceURI());
|
||||||
}
|
}
|
||||||
|
@ -538,6 +542,10 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
} else {
|
} else {
|
||||||
theEventWriter.writeStartElement(se.getName().getPrefix(), se.getName().getLocalPart(), se.getName().getNamespaceURI());
|
theEventWriter.writeStartElement(se.getName().getPrefix(), se.getName().getLocalPart(), se.getName().getNamespaceURI());
|
||||||
}
|
}
|
||||||
|
for (Iterator<?> attrIter = se.getAttributes(); attrIter.hasNext(); ) {
|
||||||
|
Attribute next = (Attribute) attrIter.next();
|
||||||
|
theEventWriter.writeAttribute(next.getName().getLocalPart(), next.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XMLStreamConstants.DTD:
|
case XMLStreamConstants.DTD:
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package ca.uhn.fhir.narrative;
|
package ca.uhn.fhir.narrative;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.hamcrest.core.StringContains;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
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.QuantityDt;
|
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
|
||||||
|
@ -15,7 +19,6 @@ 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.ObservationStatusEnum;
|
import ca.uhn.fhir.model.dstu.valueset.ObservationStatusEnum;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|
||||||
|
|
||||||
public class ThymeleafNarrativeGeneratorTest {
|
public class ThymeleafNarrativeGeneratorTest {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ThymeleafNarrativeGeneratorTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ThymeleafNarrativeGeneratorTest.class);
|
||||||
|
@ -25,10 +28,11 @@ public class ThymeleafNarrativeGeneratorTest {
|
||||||
public void before() throws IOException {
|
public void before() throws IOException {
|
||||||
gen = new ThymeleafNarrativeGenerator();
|
gen = new ThymeleafNarrativeGenerator();
|
||||||
gen.setIgnoreFailures(false);
|
gen.setIgnoreFailures(false);
|
||||||
|
gen.setIgnoreMissingTemplates(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGeneratePatient() throws DataFormatException, InternalErrorException {
|
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");
|
||||||
|
@ -44,7 +48,7 @@ public class ThymeleafNarrativeGeneratorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateDiagnosticReport() throws DataFormatException, InternalErrorException {
|
public void testGenerateDiagnosticReport() throws DataFormatException {
|
||||||
DiagnosticReport value = new DiagnosticReport();
|
DiagnosticReport value = new DiagnosticReport();
|
||||||
value.getName().setText("Some Diagnostic Report");
|
value.getName().setText("Some Diagnostic Report");
|
||||||
|
|
||||||
|
@ -58,7 +62,7 @@ public class ThymeleafNarrativeGeneratorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateDiagnosticReportWithObservations() throws DataFormatException, InternalErrorException {
|
public void testGenerateDiagnosticReportWithObservations() throws DataFormatException, IOException {
|
||||||
DiagnosticReport value = new DiagnosticReport();
|
DiagnosticReport value = new DiagnosticReport();
|
||||||
value.getName().setText("Some Diagnostic Report");
|
value.getName().setText("Some Diagnostic Report");
|
||||||
|
|
||||||
|
@ -76,6 +80,16 @@ public class ThymeleafNarrativeGeneratorTest {
|
||||||
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>"));
|
||||||
|
|
||||||
|
// Now try it with the parser
|
||||||
|
|
||||||
|
FhirContext context = new FhirContext();
|
||||||
|
context.setNarrativeGenerator(gen);
|
||||||
|
output = context.newXmlParser().setPrettyPrint(true).encodeResourceToString(value);
|
||||||
|
ourLog.info(output);
|
||||||
|
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\">Some Diagnostic Report</div>"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package ca.uhn.fhir.parser;
|
package ca.uhn.fhir.parser;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
@ -19,13 +22,17 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.Bundle;
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.BundleEntry;
|
import ca.uhn.fhir.model.api.BundleEntry;
|
||||||
import ca.uhn.fhir.model.api.UndeclaredExtension;
|
import ca.uhn.fhir.model.api.UndeclaredExtension;
|
||||||
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Organization;
|
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Specimen;
|
import ca.uhn.fhir.model.dstu.resource.Specimen;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DecimalDt;
|
import ca.uhn.fhir.model.primitive.DecimalDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||||
|
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||||
|
|
||||||
public class JsonParserTest {
|
public class JsonParserTest {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserTest.class);
|
||||||
|
@ -53,6 +60,29 @@ public class JsonParserTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNarrativeGeneration() throws DataFormatException, IOException {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
|
||||||
|
patient.addName().addFamily("Smith");
|
||||||
|
|
||||||
|
INarrativeGenerator gen = mock(INarrativeGenerator.class);
|
||||||
|
XhtmlDt xhtmlDt = new XhtmlDt("<div>help</div>");
|
||||||
|
NarrativeDt nar = new NarrativeDt(xhtmlDt, NarrativeStatusEnum.GENERATED);
|
||||||
|
when(gen.generateNarrative(eq("http://hl7.org/fhir/profiles/Patient"), eq(patient))).thenReturn(nar);
|
||||||
|
|
||||||
|
FhirContext context = new FhirContext();
|
||||||
|
context.setNarrativeGenerator(gen);
|
||||||
|
IParser p = context.newJsonParser();
|
||||||
|
p.encodeResourceToWriter(patient, new OutputStreamWriter(System.out));
|
||||||
|
String str = p.encodeResourceToString(patient);
|
||||||
|
|
||||||
|
ourLog.info(str);
|
||||||
|
|
||||||
|
assertThat(str, StringContains.containsString(",\"text\":{\"status\":\"generated\",\"div\":\"<div>help</div>\"},"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleResourceEncode() throws IOException {
|
public void testSimpleResourceEncode() throws IOException {
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ public class XmlParserTest {
|
||||||
String str = p.encodeResourceToString(rpt);
|
String str = p.encodeResourceToString(rpt);
|
||||||
|
|
||||||
ourLog.info(str);
|
ourLog.info(str);
|
||||||
assertThat(str, StringContains.containsString("<div xmlns=\"\">AAA</div>"));
|
assertThat(str, StringContains.containsString("<div xmlns=\"http://www.w3.org/1999/xhtml\">AAA</div>"));
|
||||||
assertThat(str, StringContains.containsString("reference value=\"#"));
|
assertThat(str, StringContains.containsString("reference value=\"#"));
|
||||||
|
|
||||||
int idx = str.indexOf("reference value=\"#") + "reference value=\"#".length();
|
int idx = str.indexOf("reference value=\"#") + "reference value=\"#".length();
|
||||||
|
|
Loading…
Reference in New Issue