Narrative generation continuing

This commit is contained in:
jamesagnew 2014-03-25 18:08:57 -04:00
parent 21619e5e46
commit de50244875
8 changed files with 210 additions and 108 deletions

View File

@ -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>

View File

@ -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() + "]";
}
} }

View File

@ -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));
}
} }
} }

View File

@ -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);

View File

@ -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:

View File

@ -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>"));
} }
} }

View File

@ -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 {

View File

@ -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();