Add support for comments in XML and JSON parsing/encoding

This commit is contained in:
jamesagnew 2016-02-08 22:05:17 -05:00
parent 551ec3ab16
commit 23f9292b50
30 changed files with 1766 additions and 749 deletions

View File

@ -29,14 +29,16 @@ import org.hl7.fhir.instance.model.api.IBaseDatatype;
public abstract class BaseElement implements IElement, ISupportsUndeclaredExtensions {
private List<String> myFormatCommentsPost;
private List<String> myFormatCommentsPre;
private List<ExtensionDt> myUndeclaredExtensions;
private List<ExtensionDt> myUndeclaredModifierExtensions;
@Override
public ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IBaseDatatype theValue) {
public ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl) {
Validate.notEmpty(theUrl, "URL must be populated");
Validate.notNull(theValue, "Value must not be null");
ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl, theValue);
ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl);
if (theIsModifier) {
getUndeclaredModifierExtensions();
myUndeclaredModifierExtensions.add(retVal);
@ -48,10 +50,10 @@ public abstract class BaseElement implements IElement, ISupportsUndeclaredExtens
}
@Override
public ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl) {
public ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IBaseDatatype theValue) {
Validate.notEmpty(theUrl, "URL must be populated");
ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl);
Validate.notNull(theValue, "Value must not be null");
ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl, theValue);
if (theIsModifier) {
getUndeclaredModifierExtensions();
myUndeclaredModifierExtensions.add(retVal);
@ -86,6 +88,20 @@ public abstract class BaseElement implements IElement, ISupportsUndeclaredExtens
return Collections.unmodifiableList(retVal);
}
@Override
public List<String> getFormatCommentsPost() {
if (myFormatCommentsPost == null)
myFormatCommentsPost = new ArrayList<String>();
return myFormatCommentsPost;
}
@Override
public List<String> getFormatCommentsPre() {
if (myFormatCommentsPre == null)
myFormatCommentsPre = new ArrayList<String>();
return myFormatCommentsPre;
}
@Override
public List<ExtensionDt> getUndeclaredExtensions() {
if (myUndeclaredExtensions == null) {
@ -114,9 +130,14 @@ public abstract class BaseElement implements IElement, ISupportsUndeclaredExtens
return (myUndeclaredModifierExtensions);
}
@Override
public boolean hasFormatComment() {
return (myFormatCommentsPre != null && !myFormatCommentsPre.isEmpty()) || (myFormatCommentsPost != null && !myFormatCommentsPost.isEmpty());
}
/**
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all content in this superclass instance is empty per the semantics of
* {@link #isEmpty()}.
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
*/
protected boolean isBaseEmpty() {
if (myUndeclaredExtensions != null) {

View File

@ -30,6 +30,8 @@ import java.util.Set;
import org.hl7.fhir.instance.model.api.IBase;
import ca.uhn.fhir.util.CoverageIgnore;
/**
* A collection of tags present on a single resource. TagList is backed by a {@link LinkedHashSet}, so the order of
* added tags will be consistent, but duplicates will not be preserved.
@ -253,4 +255,31 @@ public class TagList implements Set<Tag>, Serializable, IBase {
return myTagSet.toArray(theA);
}
/**
* Returns false
*/
@Override
@CoverageIgnore
public boolean hasFormatComment() {
return false;
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPre() {
throw new UnsupportedOperationException();
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPost() {
throw new UnsupportedOperationException();
}
}

View File

@ -4,6 +4,7 @@ import java.util.List;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.util.CoverageIgnore;
/*
* #%L
@ -27,6 +28,35 @@ import ca.uhn.fhir.model.api.IResource;
public abstract class BaseContainedDt implements IDatatype {
private static final long serialVersionUID = 1L;
public abstract List<? extends IResource> getContainedResources();
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPost() {
throw new UnsupportedOperationException();
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPre() {
throw new UnsupportedOperationException();
}
/**
* Returns false
*/
@Override
@CoverageIgnore
public boolean hasFormatComment() {
return false;
}
}

View File

@ -384,11 +384,11 @@ public abstract class BaseParser implements IParser {
}
}
protected String fixContainedResourceId(String theValue) {
protected IdDt fixContainedResourceId(String theValue) {
if (StringUtils.isNotBlank(theValue) && theValue.charAt(0) == '#') {
return theValue.substring(1);
return new IdDt(theValue.substring(1));
}
return theValue;
return new IdDt(theValue);
}
ContainedResources getContainedResources() {

View File

@ -158,6 +158,19 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void addToHeldComments(int valueIdx, List<String> theCommentsToAdd, ArrayList<ArrayList<String>> theListToAddTo) {
if (theCommentsToAdd.size() > 0) {
theListToAddTo.ensureCapacity(valueIdx);
while (theListToAddTo.size() <= valueIdx) {
theListToAddTo.add(null);
}
if (theListToAddTo.get(valueIdx) == null) {
theListToAddTo.set(valueIdx, new ArrayList<String>());
}
theListToAddTo.get(valueIdx).addAll(theCommentsToAdd);
}
}
private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
if (theResourceTypeObj == null) {
throw new DataFormatException("Invalid JSON content detected, missing required element: '" + thePosition + "'");
@ -203,7 +216,7 @@ public class JsonParser extends BaseParser implements IParser {
try {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
@ -536,6 +549,7 @@ public class JsonParser extends BaseParser implements IParser {
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren, boolean theContainedResource, CompositeChildElement theParent)
throws IOException {
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theChildren, theContainedResource, theParent)) {
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
@ -580,6 +594,7 @@ public class JsonParser extends BaseParser implements IParser {
ArrayList<ArrayList<HeldExtension>> extensions = new ArrayList<ArrayList<HeldExtension>>(0);
ArrayList<ArrayList<HeldExtension>> modifierExtensions = new ArrayList<ArrayList<HeldExtension>>(0);
ArrayList<ArrayList<String>> comments = new ArrayList<ArrayList<String>>(0);
int valueIdx = 0;
for (IBase nextValue : values) {
@ -654,6 +669,10 @@ public class JsonParser extends BaseParser implements IParser {
addToHeldExtensions(valueIdx, ext, extensions, true);
}
}
if (nextValue.hasFormatComment()) {
addToHeldComments(valueIdx, nextValue.getFormatCommentsPre(), comments);
addToHeldComments(valueIdx, nextValue.getFormatCommentsPost(), comments);
}
}
}
@ -665,7 +684,7 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd();
}
if (extensions.size() > 0 || modifierExtensions.size() > 0) {
if (!extensions.isEmpty() || !modifierExtensions.isEmpty() || !comments.isEmpty()) {
if (inArray) {
// If this is a repeatable field, the extensions go in an array too
theEventWriter.writeStartArray('_' + currentChildName);
@ -687,6 +706,16 @@ public class JsonParser extends BaseParser implements IParser {
haveContent = true;
heldModExts = modifierExtensions.get(i);
}
ArrayList<String> nextComments;
if (comments.size() > i) {
nextComments = comments.get(i);
} else {
nextComments = null;
}
if (nextComments != null && nextComments.isEmpty() == false) {
haveContent = true;
}
if (!haveContent) {
theEventWriter.writeNull();
@ -694,6 +723,13 @@ public class JsonParser extends BaseParser implements IParser {
if (inArray) {
theEventWriter.writeStartObject();
}
if (nextComments != null && !nextComments.isEmpty()) {
theEventWriter.writeStartArray("fhir_comments");
for (String next : nextComments) {
theEventWriter.write(next);
}
theEventWriter.writeEnd();
}
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts, null);
if (inArray) {
theEventWriter.writeEnd();
@ -708,13 +744,35 @@ public class JsonParser extends BaseParser implements IParser {
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theContainedResource, CompositeChildElement theParent)
throws IOException, DataFormatException {
writeCommentsPreAndPost(theNextValue, theEventWriter);
extractAndWriteExtensionsAsDirectChild(theNextValue, theEventWriter, resDef, theResDef, theResource, null);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theContainedResource, theParent);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theContainedResource, theParent);
}
private void writeCommentsPreAndPost(IBase theNextValue, JsonGenerator theEventWriter) {
if (theNextValue.hasFormatComment()) {
theEventWriter.writeStartArray("fhir_comments");
List<String> pre = theNextValue.getFormatCommentsPre();
if (pre.isEmpty()==false) {
for (String next : pre) {
theEventWriter.write(next);
}
}
List<String> post = theNextValue.getFormatCommentsPost();
if (post.isEmpty()==false) {
for (String next : post) {
theEventWriter.write(next);
}
}
theEventWriter.writeEnd();
}
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource) throws IOException {
String resourceId = null;
IIdType resourceId = null;
// if (theResource instanceof IResource) {
// IResource res = (IResource) theResource;
// if (StringUtils.isNotBlank(res.getId().getIdPart())) {
@ -732,7 +790,7 @@ public class JsonParser extends BaseParser implements IParser {
// }
if (StringUtils.isNotBlank(theResource.getIdElement().getIdPart())) {
resourceId = theResource.getIdElement().getIdPart();
resourceId = theResource.getIdElement();
if (theResource.getIdElement().getValue().startsWith("urn:")) {
resourceId = null;
}
@ -748,7 +806,7 @@ public class JsonParser extends BaseParser implements IParser {
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, resourceId);
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource, String theResourceId) throws IOException {
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource, IIdType theResourceId) throws IOException {
if (!theContainedResource) {
super.containResourcesForEncoding(theResource);
}
@ -762,8 +820,13 @@ public class JsonParser extends BaseParser implements IParser {
}
theEventWriter.write("resourceType", resDef.getName());
if (theResourceId != null) {
theEventWriter.write("id", theResourceId);
if (theResourceId != null && theResourceId.hasIdPart()) {
theEventWriter.write("id", theResourceId.getIdPart());
if (theResourceId.hasFormatComment()) {
theEventWriter.writeStartObject("_id");
writeCommentsPreAndPost(theResourceId, theEventWriter);
theEventWriter.writeEnd();
}
}
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) {
@ -1001,6 +1064,8 @@ public class JsonParser extends BaseParser implements IParser {
default:
break;
}
} else if ("fhir_comments".equals(nextKey)) {
parseFhirComments(nextEntry.getValue(), theState);
}
}
}
@ -1118,7 +1183,9 @@ public class JsonParser extends BaseParser implements IParser {
private void parseChildren(JsonObject theObject, ParserState<?> theState) {
String elementId = null;
for (String nextName : theObject.keySet()) {
Set<String> keySet = theObject.keySet();
for (String nextName : keySet) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("id".equals(nextName)) {
@ -1146,6 +1213,9 @@ public class JsonParser extends BaseParser implements IParser {
JsonArray array = grabJsonArray(theObject, nextName, "modifierExtension");
parseExtension(theState, array, true);
continue;
} else if (nextName.equals("fhir_comments")) {
parseFhirComments(theObject.get(nextName), theState);
continue;
} else if (nextName.charAt(0) == '_') {
continue;
}
@ -1168,6 +1238,19 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void parseFhirComments(JsonValue theObject, ParserState<?> theState) {
if (theObject.getValueType() == ValueType.ARRAY) {
for (JsonValue nextComment : ((JsonArray)theObject)) {
if (nextComment.getValueType() == ValueType.STRING) {
String commentText = ((JsonString)nextComment).getString();
if (commentText != null) {
theState.commentPre(commentText);
}
}
}
}
}
private JsonArray grabJsonArray(JsonObject theObject, String nextName, String thePosition) {
JsonValue object = theObject.get(nextName);
if (object == null) {
@ -1467,6 +1550,9 @@ public class JsonParser extends BaseParser implements IParser {
writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, myUndeclaredExtension);
} else {
theEventWriter.writeStartObject();
writeCommentsPreAndPost(myValue, theEventWriter);
theEventWriter.write("url", myDef.getExtensionUrl());
BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
@ -1486,6 +1572,9 @@ public class JsonParser extends BaseParser implements IParser {
String extensionUrl = ext.getUrl();
theEventWriter.writeStartObject();
writeCommentsPreAndPost(myUndeclaredExtension, theEventWriter);
theEventWriter.write("url", extensionUrl);
boolean noValue = value == null || value.isEmpty();

View File

@ -89,11 +89,13 @@ import ca.uhn.fhir.util.IModelVisitor;
class ParserState<T> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private List<String> myComments = new ArrayList<String>(2);
private FhirContext myContext;
private IParserErrorHandler myErrorHandler;
private boolean myJsonMode;
private T myObject;
private BaseState myState;
private IParserErrorHandler myErrorHandler;
private IBase myPreviousElement;
private ParserState(FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
myContext = theContext;
@ -105,6 +107,29 @@ class ParserState<T> {
myState.attributeValue(theName, theValue);
}
public void commentPost(String theCommentText) {
if (myPreviousElement != null) {
myPreviousElement.getFormatCommentsPost().add(theCommentText);
}
}
public void commentPre(String theCommentText) {
if (myState.getCurrentElement() != null) {
IBase element = myState.getCurrentElement();
element.getFormatCommentsPre().add(theCommentText);
}
}
private BaseState createResourceReferenceState(ParserState<T>.PreResourceState thePreResourceState, IBase newChildInstance) {
BaseState newState;
if (newChildInstance instanceof IBaseReference) {
newState = new ResourceReferenceStateHl7Org(thePreResourceState, (IBaseReference) newChildInstance);
} else {
newState = new ResourceReferenceStateHapi(thePreResourceState, (BaseResourceReferenceDt) newChildInstance);
}
return newState;
}
public void endingElement() throws DataFormatException {
myState.endingElement();
}
@ -119,7 +144,8 @@ class ParserState<T> {
@SuppressWarnings("unchecked")
public T getObject() {
return (T) myState.getCurrentElement();
IBase retVal = myState.getCurrentElement();
return (T) retVal;
}
public boolean isComplete() {
@ -159,6 +185,7 @@ class ParserState<T> {
}
private void pop() {
myPreviousElement = myState.getCurrentElement();
myState = myState.myStack;
myState.wereBack();
}
@ -166,6 +193,12 @@ class ParserState<T> {
private void push(BaseState theState) {
theState.setStack(myState);
myState = theState;
if (myComments.isEmpty() == false) {
if (myState.getCurrentElement() != null) {
myState.getCurrentElement().getFormatCommentsPre().addAll(myComments);
myComments.clear();
}
}
}
private void putPlacerResourceInDeletedEntry(BundleEntry entry) {
@ -206,14 +239,14 @@ class ParserState<T> {
}
/**
* Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically intended for embedded XHTML content
* Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically
* intended for embedded XHTML content
*/
public void xmlEvent(XMLEvent theNextEvent) {
myState.xmlEvent(theNextEvent);
}
static ParserState<Bundle> getPreAtomInstance(FhirContext theContext, Class<? extends IBaseResource> theResourceType, boolean theJsonMode, IParserErrorHandler theErrorHandler)
throws DataFormatException {
static ParserState<Bundle> getPreAtomInstance(FhirContext theContext, Class<? extends IBaseResource> theResourceType, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException {
ParserState<Bundle> retVal = new ParserState<Bundle>(theContext, theJsonMode, theErrorHandler);
if (theContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
retVal.push(retVal.new PreAtomState(theResourceType));
@ -227,8 +260,7 @@ class ParserState<T> {
* @param theResourceType
* May be null
*/
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler)
throws DataFormatException {
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException {
ParserState<T> retVal = new ParserState<T>(theContext, theJsonMode, theErrorHandler);
if (theResourceType == null) {
if (theContext.getVersion().getVersion().isRi()) {
@ -307,7 +339,8 @@ class ParserState<T> {
myScheme = theValue;
} else if ("value".equals(theName)) {
/*
* This handles XML parsing, which is odd for this quasi-resource type, since the tag has three values instead of one like everything else.
* This handles XML parsing, which is odd for this quasi-resource type, since the tag has three values
* instead of one like everything else.
*/
switch (myCatState) {
case STATE_LABEL:
@ -807,11 +840,6 @@ class ParserState<T> {
// ignore by default
}
protected void logAndSwallowUnexpectedElement(String theLocalPart) {
myErrorHandler.unknownElement(null, theLocalPart);
push(new SwallowChildrenWholeState(getPreResourceState()));
}
/**
* @param theNamespaceUri
* The XML namespace (if XML) or null
@ -866,6 +894,11 @@ class ParserState<T> {
return false;
}
protected void logAndSwallowUnexpectedElement(String theLocalPart) {
myErrorHandler.unknownElement(null, theLocalPart);
push(new SwallowChildrenWholeState(getPreResourceState()));
}
public void setStack(BaseState theState) {
myStack = theState;
}
@ -1039,8 +1072,8 @@ class ParserState<T> {
private class BundleEntryState extends BaseState {
private BundleEntry myEntry;
private Class<? extends IBaseResource> myResourceType;
private IdDt myFullUrl;
private Class<? extends IBaseResource> myResourceType;
public BundleEntryState(Bundle theInstance, Class<? extends IBaseResource> theResourceType) {
super(null);
@ -1095,7 +1128,7 @@ class ParserState<T> {
if (id != null && id.isEmpty() == false) {
myEntry.getResource().setId(id);
}
if (myFullUrl != null && !myFullUrl.isEmpty()) {
myEntry.getResource().setId(myFullUrl);
}
@ -1171,7 +1204,6 @@ class ParserState<T> {
}
private class BundleLinkState extends BaseState {
private BundleEntry myEntry;
@ -1248,7 +1280,7 @@ class ParserState<T> {
}
}
private class BundleState extends BaseState {
private Bundle myInstance;
@ -1518,16 +1550,6 @@ class ParserState<T> {
}
private BaseState createResourceReferenceState(ParserState<T>.PreResourceState thePreResourceState, IBase newChildInstance) {
BaseState newState;
if (newChildInstance instanceof IBaseReference) {
newState = new ResourceReferenceStateHl7Org(thePreResourceState, (IBaseReference) newChildInstance);
} else {
newState = new ResourceReferenceStateHapi(thePreResourceState, (BaseResourceReferenceDt) newChildInstance);
}
return newState;
}
private class ElementCompositeState extends BaseState {
private BaseRuntimeElementCompositeDefinition<?> myDefinition;
@ -1573,7 +1595,8 @@ class ParserState<T> {
child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName);
} catch (DataFormatException e) {
/*
* This means we've found an element that doesn't exist on the structure. If the error handler doesn't throw an exception, swallow the element silently along with any child elements
* This means we've found an element that doesn't exist on the structure. If the error handler doesn't throw
* an exception, swallow the element silently along with any child elements
*/
myErrorHandler.unknownElement(null, theChildName);
push(new SwallowChildrenWholeState(getPreResourceState()));
@ -1783,19 +1806,6 @@ class ParserState<T> {
}
private class SecurityLabelElementStateHapi extends ElementCompositeState {
public SecurityLabelElementStateHapi(ParserState<T>.PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBase codingDt) {
super(thePreResourceState, theDef, codingDt);
}
@Override
public void endingElement() throws DataFormatException {
pop();
}
}
private class MetaElementState extends BaseState {
private ResourceMetadataMap myMap;
@ -1932,120 +1942,13 @@ class ParserState<T> {
}
private class PreResourceStateHapi extends PreResourceState {
private BundleEntry myEntry;
private Object myTarget;
private IMutator myMutator;
public PreResourceStateHapi(BundleEntry theEntry, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myEntry = theEntry;
}
public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myTarget = theTarget;
myMutator = theMutator;
}
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
}
@SuppressWarnings("unchecked")
@Override
public void wereBack() {
super.wereBack();
if (myEntry == null && myMutator == null) {
myObject = (T) getCurrentElement();
}
IResource nextResource = (IResource) getCurrentElement();
String version = ResourceMetadataKeyEnum.VERSION.get(nextResource);
String resourceName = myContext.getResourceDefinition(nextResource).getName();
String bundleIdPart = nextResource.getId().getIdPart();
if (isNotBlank(bundleIdPart)) {
// if (isNotBlank(entryBaseUrl)) {
// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
// } else {
nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
// }
}
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceUri, theLocalPart);
if (myEntry != null) {
myEntry.setResource((IResource) getCurrentElement());
}
if (myMutator != null) {
myMutator.addValue(myTarget, getCurrentElement());
}
}
}
private class PreResourceStateHl7Org extends PreResourceState {
private IMutator myMutator;
private Object myTarget;
public PreResourceStateHl7Org(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myMutator = theMutator;
myTarget = theTarget;
}
public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
}
@SuppressWarnings("unchecked")
@Override
public void wereBack() {
super.wereBack();
if (myTarget == null) {
myObject = (T) getCurrentElement();
}
if (getCurrentElement() instanceof IDomainResource) {
IDomainResource elem = (IDomainResource) getCurrentElement();
String resourceName = myContext.getResourceDefinition(elem).getName();
String versionId = elem.getMeta().getVersionId();
if (StringUtils.isBlank(elem.getIdElement().getIdPart())) {
// Resource has no ID
} else if (StringUtils.isNotBlank(versionId)) {
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart() + "/_history/" + versionId);
} else {
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart());
}
}
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceUri, theLocalPart);
if (myMutator != null) {
myMutator.addValue(myTarget, getCurrentElement());
}
}
}
private abstract class PreResourceState extends BaseState {
private Map<String, IBaseResource> myContainedResources = new HashMap<String, IBaseResource>();
private IBaseResource myInstance;
private FhirVersionEnum myParentVersion;
private Class<? extends IBaseResource> myResourceType;
private boolean myRequireResourceType = true;
public ParserState<T>.PreResourceState setRequireResourceType(boolean theRequireResourceType) {
myRequireResourceType = theRequireResourceType;
return this;
}
private Class<? extends IBaseResource> myResourceType;
public PreResourceState(Class<? extends IBaseResource> theResourceType) {
super(null);
@ -2124,6 +2027,11 @@ class ParserState<T> {
return true;
}
public ParserState<T>.PreResourceState setRequireResourceType(boolean theRequireResourceType) {
myRequireResourceType = theRequireResourceType;
return this;
}
@Override
public void wereBack() {
final boolean bundle = "Bundle".equals(myContext.getResourceDefinition(myInstance).getName());
@ -2163,8 +2071,7 @@ class ParserState<T> {
}
@Override
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
acceptElement(theNextExt.getValue(), null, null, null);
}
});
@ -2202,6 +2109,108 @@ class ParserState<T> {
}
private class PreResourceStateHapi extends PreResourceState {
private BundleEntry myEntry;
private IMutator myMutator;
private Object myTarget;
public PreResourceStateHapi(BundleEntry theEntry, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myEntry = theEntry;
}
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
}
public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myTarget = theTarget;
myMutator = theMutator;
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceUri, theLocalPart);
if (myEntry != null) {
myEntry.setResource((IResource) getCurrentElement());
}
if (myMutator != null) {
myMutator.addValue(myTarget, getCurrentElement());
}
}
@SuppressWarnings("unchecked")
@Override
public void wereBack() {
super.wereBack();
if (myEntry == null && myMutator == null) {
myObject = (T) getCurrentElement();
}
IResource nextResource = (IResource) getCurrentElement();
String version = ResourceMetadataKeyEnum.VERSION.get(nextResource);
String resourceName = myContext.getResourceDefinition(nextResource).getName();
String bundleIdPart = nextResource.getId().getIdPart();
if (isNotBlank(bundleIdPart)) {
// if (isNotBlank(entryBaseUrl)) {
// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
// } else {
nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
// }
}
}
}
private class PreResourceStateHl7Org extends PreResourceState {
private IMutator myMutator;
private Object myTarget;
public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
}
public PreResourceStateHl7Org(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myMutator = theMutator;
myTarget = theTarget;
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceUri, theLocalPart);
if (myMutator != null) {
myMutator.addValue(myTarget, getCurrentElement());
}
}
@SuppressWarnings("unchecked")
@Override
public void wereBack() {
super.wereBack();
if (myTarget == null) {
myObject = (T) getCurrentElement();
}
if (getCurrentElement() instanceof IDomainResource) {
IDomainResource elem = (IDomainResource) getCurrentElement();
String resourceName = myContext.getResourceDefinition(elem).getName();
String versionId = elem.getMeta().getVersionId();
if (StringUtils.isBlank(elem.getIdElement().getIdPart())) {
// Resource has no ID
} else if (StringUtils.isNotBlank(versionId)) {
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart() + "/_history/" + versionId);
} else {
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart());
}
}
}
}
private class PreTagListState extends BaseState {
private TagList myTagList;
@ -2300,6 +2309,75 @@ class ParserState<T> {
}
private class ResourceReferenceStateHapi extends BaseState {
private BaseResourceReferenceDt myInstance;
private ResourceReferenceSubState mySubState;
public ResourceReferenceStateHapi(PreResourceState thePreResourceState, BaseResourceReferenceDt theInstance) {
super(thePreResourceState);
myInstance = theInstance;
mySubState = ResourceReferenceSubState.INITIAL;
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
if (!"value".equals(theName)) {
return;
}
switch (mySubState) {
case DISPLAY:
myInstance.getDisplayElement().setValue(theValue);
break;
case INITIAL:
throw new DataFormatException("Unexpected attribute: " + theValue);
case REFERENCE:
myInstance.getReference().setValue(theValue);
break;
}
}
@Override
public void endingElement() {
switch (mySubState) {
case INITIAL:
pop();
break;
case DISPLAY:
case REFERENCE:
mySubState = ResourceReferenceSubState.INITIAL;
}
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
switch (mySubState) {
case INITIAL:
if ("display".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.DISPLAY;
break;
} else if ("reference".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
} else if ("resource".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
}
//$FALL-THROUGH$
case DISPLAY:
case REFERENCE:
throw new DataFormatException("Unexpected element: " + theLocalPart);
}
}
@Override
protected IElement getCurrentElement() {
return myInstance;
}
}
private class ResourceReferenceStateHl7Org extends BaseState {
private IBaseReference myInstance;
@ -2372,75 +2450,6 @@ class ParserState<T> {
}
private class ResourceReferenceStateHapi extends BaseState {
private BaseResourceReferenceDt myInstance;
private ResourceReferenceSubState mySubState;
public ResourceReferenceStateHapi(PreResourceState thePreResourceState, BaseResourceReferenceDt theInstance) {
super(thePreResourceState);
myInstance = theInstance;
mySubState = ResourceReferenceSubState.INITIAL;
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
if (!"value".equals(theName)) {
return;
}
switch (mySubState) {
case DISPLAY:
myInstance.getDisplayElement().setValue(theValue);
break;
case INITIAL:
throw new DataFormatException("Unexpected attribute: " + theValue);
case REFERENCE:
myInstance.getReference().setValue(theValue);
break;
}
}
@Override
public void endingElement() {
switch (mySubState) {
case INITIAL:
pop();
break;
case DISPLAY:
case REFERENCE:
mySubState = ResourceReferenceSubState.INITIAL;
}
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
switch (mySubState) {
case INITIAL:
if ("display".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.DISPLAY;
break;
} else if ("reference".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
} else if ("resource".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
}
//$FALL-THROUGH$
case DISPLAY:
case REFERENCE:
throw new DataFormatException("Unexpected element: " + theLocalPart);
}
}
@Override
protected IElement getCurrentElement() {
return myInstance;
}
}
private enum ResourceReferenceSubState {
DISPLAY, INITIAL, REFERENCE
}
@ -2474,6 +2483,19 @@ class ParserState<T> {
}
private class SecurityLabelElementStateHapi extends ElementCompositeState {
public SecurityLabelElementStateHapi(ParserState<T>.PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBase codingDt) {
super(thePreResourceState, theDef, codingDt);
}
@Override
public void endingElement() throws DataFormatException {
pop();
}
}
private class SwallowChildrenWholeState extends BaseState {
private int myDepth;
@ -2482,6 +2504,11 @@ class ParserState<T> {
super(thePreResourceState);
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
// ignore
}
@Override
public void endingElement() throws DataFormatException {
myDepth--;
@ -2490,11 +2517,6 @@ class ParserState<T> {
}
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
// ignore
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
myDepth++;
@ -2521,11 +2543,6 @@ class ParserState<T> {
pop();
}
@Override
protected IBase getCurrentElement() {
return myTagList;
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
if (TagList.ATTR_CATEGORY.equals(theLocalPart)) {
@ -2535,6 +2552,11 @@ class ParserState<T> {
}
}
@Override
protected IBase getCurrentElement() {
return myTagList;
}
}
private class TagState extends BaseState {
@ -2608,25 +2630,6 @@ class ParserState<T> {
}
private class XhtmlStateHl7Org extends XhtmlState {
private IBaseXhtml myHl7OrgDatatype;
private XhtmlStateHl7Org(PreResourceState thePreResourceState, IBaseXhtml theHl7OrgDatatype) {
super(thePreResourceState, new XhtmlDt(), true);
myHl7OrgDatatype = theHl7OrgDatatype;
}
@Override
public void doPop() {
// TODO: this is not very efficient
String value = getDt().getValueAsString();
myHl7OrgDatatype.setValueAsString(value);
super.doPop();
}
}
private class XhtmlState extends BaseState {
private int myDepth;
private XhtmlDt myDt;
@ -2640,15 +2643,6 @@ class ParserState<T> {
myIncludeOuterEvent = theIncludeOuterEvent;
}
public XhtmlDt getDt() {
return myDt;
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
// IGNORE - don't handle this as an error, we process these as XML events
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
if (myJsonMode) {
@ -2672,11 +2666,20 @@ class ParserState<T> {
super.endingElement();
}
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
// IGNORE - don't handle this as an error, we process these as XML events
}
@Override
protected IElement getCurrentElement() {
return myDt;
}
public XhtmlDt getDt() {
return myDt;
}
@Override
public void xmlEvent(XMLEvent theEvent) {
if (theEvent.isEndElement()) {
@ -2701,4 +2704,23 @@ class ParserState<T> {
}
private class XhtmlStateHl7Org extends XhtmlState {
private IBaseXhtml myHl7OrgDatatype;
private XhtmlStateHl7Org(PreResourceState thePreResourceState, IBaseXhtml theHl7OrgDatatype) {
super(thePreResourceState, new XhtmlDt(), true);
myHl7OrgDatatype = theHl7OrgDatatype;
}
@Override
public void doPop() {
// TODO: this is not very efficient
String value = getDt().getValueAsString();
myHl7OrgDatatype.setValueAsString(value);
super.doPop();
}
}
}

View File

@ -197,10 +197,14 @@ public class XmlParser extends BaseParser implements IParser {
ourLog.trace("Entering XML parsing loop with state: {}", parserState);
try {
List<String> heldComments = new ArrayList<String>(1);
while (streamReader.hasNext()) {
XMLEvent nextEvent = streamReader.nextEvent();
try {
if (nextEvent.isStartElement()) {
switch (nextEvent.getEventType()) {
case XMLStreamConstants.START_ELEMENT: {
StartElement elem = nextEvent.asStartElement();
String namespaceURI = elem.getName().getNamespaceURI();
@ -218,10 +222,15 @@ public class XmlParser extends BaseParser implements IParser {
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), true);
} else {
String elementName = elem.getName().getLocalPart();
parserState.enteringNewElement(namespaceURI, elementName);
}
if (!heldComments.isEmpty()) {
for (String next : heldComments) {
parserState.commentPre(next);
}
heldComments.clear();
}
@SuppressWarnings("unchecked")
@ -231,19 +240,39 @@ public class XmlParser extends BaseParser implements IParser {
parserState.attributeValue(next.getName().getLocalPart(), next.getValue());
}
} else if (nextEvent.isAttribute()) {
break;
}
case XMLStreamConstants.ATTRIBUTE: {
Attribute elem = (Attribute) nextEvent;
String name = (elem.getName().getLocalPart());
parserState.attributeValue(name, elem.getValue());
} else if (nextEvent.isEndElement()) {
break;
}
case XMLStreamConstants.END_ELEMENT: {
if (!heldComments.isEmpty()) {
for (String next : heldComments) {
parserState.commentPost(next);
}
heldComments.clear();
}
parserState.endingElement();
if (parserState.isComplete()) {
return parserState.getObject();
}
} else if (nextEvent.isCharacters()) {
parserState.string(nextEvent.asCharacters().getData());
break;
}
case XMLStreamConstants.CHARACTERS: {
parserState.string(nextEvent.asCharacters().getData());
break;
}
case XMLStreamConstants.COMMENT: {
Comment comment = (Comment) nextEvent;
String commentText = comment.getText();
heldComments.add(commentText);
break;
}
}
parserState.xmlEvent(nextEvent);
} catch (DataFormatException e) {
@ -468,9 +497,9 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.close();
}
private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef,
private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase theElement, String childName, BaseRuntimeElementDefinition<?> childDef,
String theExtensionUrl, boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
if (nextValue == null || nextValue.isEmpty()) {
if (theElement == null || theElement.isEmpty()) {
if (isChildContained(childDef, theIncludedResource)) {
// We still want to go in..
} else {
@ -478,25 +507,27 @@ public class XmlParser extends BaseParser implements IParser {
}
}
writeCommentsPre(theEventWriter, theElement);
switch (childDef.getChildType()) {
case ID_DATATYPE: {
IIdType value = (IIdType) nextValue;
IIdType value = (IIdType) theElement;
String encodedValue = "id".equals(childName) ? value.getIdPart() : value.getValue();
if (value != null) {
theEventWriter.writeStartElement(childName);
theEventWriter.writeAttribute("value", encodedValue);
encodeExtensionsIfPresent(theResource, theEventWriter, nextValue, theIncludedResource);
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource);
theEventWriter.writeEndElement();
}
break;
}
case PRIMITIVE_DATATYPE: {
IPrimitiveType<?> pd = (IPrimitiveType<?>) nextValue;
IPrimitiveType<?> pd = (IPrimitiveType<?>) theElement;
String value = pd.getValueAsString();
if (value != null) {
theEventWriter.writeStartElement(childName);
theEventWriter.writeAttribute("value", value);
encodeExtensionsIfPresent(theResource, theEventWriter, nextValue, theIncludedResource);
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource);
theEventWriter.writeEndElement();
}
break;
@ -508,12 +539,12 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.writeAttribute("url", theExtensionUrl);
}
BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef;
encodeCompositeElementToStreamWriter(theResource, nextValue, theEventWriter, childCompositeDef, theIncludedResource, theParent);
encodeCompositeElementToStreamWriter(theResource, theElement, theEventWriter, childCompositeDef, theIncludedResource, theParent);
theEventWriter.writeEndElement();
break;
}
case RESOURCE_REF: {
IBaseReference ref = (IBaseReference) nextValue;
IBaseReference ref = (IBaseReference) theElement;
if (!ref.isEmpty()) {
theEventWriter.writeStartElement(childName);
encodeResourceReferenceToStreamWriter(theEventWriter, ref, theResource, theIncludedResource);
@ -538,20 +569,20 @@ public class XmlParser extends BaseParser implements IParser {
}
case RESOURCE: {
theEventWriter.writeStartElement(childName);
IBaseResource resource = (IBaseResource) nextValue;
IBaseResource resource = (IBaseResource) theElement;
encodeResourceToXmlStreamWriter(resource, theEventWriter, false);
theEventWriter.writeEndElement();
break;
}
case PRIMITIVE_XHTML: {
XhtmlDt dt = (XhtmlDt) nextValue;
XhtmlDt dt = (XhtmlDt) theElement;
if (dt.hasContent()) {
encodeXhtml(dt, theEventWriter);
}
break;
}
case PRIMITIVE_XHTML_HL7ORG: {
IBaseXhtml dt = (IBaseXhtml) nextValue;
IBaseXhtml dt = (IBaseXhtml) theElement;
if (dt.isEmpty()) {
break;
} else {
@ -568,6 +599,28 @@ public class XmlParser extends BaseParser implements IParser {
}
}
writeCommentsPost(theEventWriter, theElement);
}
private void writeCommentsPre(XMLStreamWriter theEventWriter, IBase theElement) throws XMLStreamException {
if (theElement != null && theElement.hasFormatComment()) {
for (String next : theElement.getFormatCommentsPre()) {
if (isNotBlank(next)) {
theEventWriter.writeComment(next);
}
}
}
}
private void writeCommentsPost(XMLStreamWriter theEventWriter, IBase theElement) throws XMLStreamException {
if (theElement != null && theElement.hasFormatComment()) {
for (String next : theElement.getFormatCommentsPost()) {
if (isNotBlank(next)) {
theEventWriter.writeComment(next);
}
}
}
}
private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren,
@ -719,23 +772,10 @@ public class XmlParser extends BaseParser implements IParser {
}
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
String resourceId = null;
// if (theResource instanceof IResource) {
// // HAPI structs
// IResource iResource = (IResource) theResource;
// if (StringUtils.isNotBlank(iResource.getId().getIdPart())) {
// resourceId = iResource.getId().getIdPart();
// }
// } else {
// // HL7 structs
// IAnyResource resource = (IAnyResource) theResource;
// if (StringUtils.isNotBlank(resource.getIdElement().getIdPart())) {
// resourceId = resource.getIdElement().getIdPart();
// }
// }
IIdType resourceId = null;
if (StringUtils.isNotBlank(theResource.getIdElement().getIdPart())) {
resourceId = theResource.getIdElement().getIdPart();
resourceId = theResource.getIdElement();
if (theResource.getIdElement().getValue().startsWith("urn:")) {
resourceId = null;
}
@ -751,7 +791,7 @@ public class XmlParser extends BaseParser implements IParser {
encodeResourceToXmlStreamWriter(theResource, theEventWriter, theIncludedResource, resourceId);
}
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, String theResourceId) throws XMLStreamException {
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, IIdType theResourceId) throws XMLStreamException {
if (!theContainedResource) {
super.containResourcesForEncoding(theResource);
}
@ -767,7 +807,12 @@ public class XmlParser extends BaseParser implements IParser {
if (theResource instanceof IAnyResource) {
// HL7.org Structures
writeOptionalTagWithValue(theEventWriter, "id", theResourceId);
if (theResourceId != null) {
writeCommentsPre(theEventWriter, theResourceId);
writeOptionalTagWithValue(theEventWriter, "id", theResourceId.getIdPart());
writeCommentsPost(theEventWriter, theResourceId);
}
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource, new CompositeChildElement(resDef));
} else {
@ -777,8 +822,12 @@ public class XmlParser extends BaseParser implements IParser {
// DSTU2+
IResource resource = (IResource) theResource;
writeOptionalTagWithValue(theEventWriter, "id", theResourceId);
if (theResourceId != null) {
writeCommentsPre(theEventWriter, theResourceId);
writeOptionalTagWithValue(theEventWriter, "id", theResourceId.getIdPart());
writeCommentsPost(theEventWriter, theResourceId);
}
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
String versionIdPart = resourceId.getVersionIdPart();
@ -833,8 +882,8 @@ public class XmlParser extends BaseParser implements IParser {
} else {
// DSTU1
if (theResourceId != null && theContainedResource) {
theEventWriter.writeAttribute("id", theResourceId);
if (theResourceId != null && theContainedResource && theResourceId.hasIdPart()) {
theEventWriter.writeAttribute("id", theResourceId.getIdPart());
}
if (theResource instanceof IBaseBinary) {
@ -892,6 +941,8 @@ public class XmlParser extends BaseParser implements IParser {
continue;
}
writeCommentsPre(theWriter, next);
theWriter.writeStartElement(tagName);
String url = next.getUrl();
@ -922,6 +973,9 @@ public class XmlParser extends BaseParser implements IParser {
encodeExtensionsIfPresent(theResource, theWriter, next, theIncludedResource);
theWriter.writeEndElement();
writeCommentsPost(theWriter, next);
}
}

View File

@ -1,31 +1,9 @@
package ca.uhn.fhir.rest.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.api.IBase;
/**
* Validation mode parameter for the $validate operation (DSTU2+ only)
*/
public enum ValidationModeEnum implements IBase {
public enum ValidationModeEnum {
/**
* The server checks the content, and then checks that the content would be acceptable as a create (e.g. that the content would not validate any uniqueness constraints)
*/
@ -41,8 +19,8 @@ public enum ValidationModeEnum implements IBase {
*/
DELETE;
@Override
public boolean isEmpty() {
return false;
}
// @Override
// public boolean isEmpty() {
// return false;
// }
}

View File

@ -132,6 +132,8 @@ public class OperationParameter implements IParameter {
myParamType = "date";
myMax = 2;
myAllowGet = true;
} else if (myParameterType.equals(ValidationModeEnum.class)) {
// this is ok
} else if (!IBase.class.isAssignableFrom(myParameterType) || myParameterType.isInterface() || Modifier.isAbstract(myParameterType.getModifiers())) {
throw new ConfigurationException("Invalid type for @OperationParam: " + myParameterType.getName());
} else if (myParameterType.equals(ValidationModeEnum.class)) {

View File

@ -121,6 +121,7 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
@Override
public void writeComment(String theData) throws XMLStreamException {
indent();
myTarget.writeComment(theData);
}

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.instance.model.api;
import java.io.Serializable;
import java.util.List;
/*
* #%L
@ -31,4 +32,28 @@ public interface IBase extends Serializable {
boolean isEmpty();
/**
* Returns <code>true</code> if any comments would be returned by {@link #getFormatCommentsPre()}
* or {@link #getFormatCommentsPost()}
*
* @since 1.5
*/
boolean hasFormatComment();
/**
* Returns a list of comments appearing immediately before this element within the serialized
* form of the resource. Creates the list if it does not exist, so this method will not return <code>null</code>
*
* @since 1.5
*/
List<String> getFormatCommentsPre();
/**
* Returns a list of comments appearing immediately after this element within the serialized
* form of the resource. Creates the list if it does not exist, so this method will not return <code>null</code>
*
* @since 1.5
*/
List<String> getFormatCommentsPost();
}

View File

@ -32,7 +32,7 @@ package org.hl7.fhir.instance.model.api;
* which version of the strctures your application is using.
* </p>
*/
public interface IIdType {
public interface IIdType extends IBase {
void applyTo(IBaseResource theResource);

View File

@ -26,34 +26,29 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
//@formatter:off
@Table(name="TRM_VALUESET", uniqueConstraints= {
@UniqueConstraint(name="IDX_VS_URI", columnNames= {"VS_URI"})
@Table(name="TRM_CODESYSTEM", uniqueConstraints= {
@UniqueConstraint(name="IDX_CS_RESOURCEPID", columnNames= {"RES_ID"})
})
@Entity()
//@formatter:on
public class TermValueSet implements Serializable {
public class TermCodeSystem implements Serializable {
private static final long serialVersionUID = 1L;
@Id()
@SequenceGenerator(name="SEQ_VALUESET_PID", sequenceName="SEQ_VALUESET_PID")
@SequenceGenerator(name="SEQ_CODESYSTEM_PID", sequenceName="SEQ_CODESYSTEM_PID")
@GeneratedValue()
@Column(name="PID")
private Long myPid;
@Column(name="VS_URI", length=200)
private String myUri;
@OneToOne()
@JoinColumn(name="RES_ID", referencedColumnName="RES_ID", nullable=false, updatable=false)
private ResourceTable myResource;
public String getUri() {
return myUri;
}
public void setUri(String theUri) {
myUri = theUri;
}
}

View File

@ -23,13 +23,17 @@ package ca.uhn.fhir.jpa.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
@Entity
@Table(name="TRM_CONCEPT")
public class TermConcept implements Serializable {
private static final long serialVersionUID = 1L;
@ -40,7 +44,13 @@ public class TermConcept implements Serializable {
private Long myPid;
@ManyToOne()
@JoinColumn(name="VS_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_CONCEPT_PID_VS_PID"))
private TermValueSet myValueSet;
@JoinColumn(name="CODESYSTEM_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_CONCEPT_PID_CS_PID"))
private TermCodeSystem myCodeSystem;
@Column(name="CODE", length=100, nullable=false)
private String myCode;
@Column(name="DISPLAY", length=200, nullable=true)
private String myDisplay;
}

View File

@ -284,6 +284,21 @@ public class ServerInvalidDefinitionTest {
public IBaseResource setId(IIdType theId) {
return null;
}
@Override
public boolean hasFormatComment() {
return false;
}
@Override
public List<String> getFormatCommentsPre() {
return null;
}
@Override
public List<String> getFormatCommentsPost() {
return null;
}
}.getClass();
}

View File

@ -34,6 +34,7 @@
},
"identifier":[
{
"fhir_comments":[" MRN assigned by ACME healthcare on 6-May 2001 "],
"use":"usual",
"label":"MRN",
"system":"urn:oid:1.2.36.146.595.217.0.1",
@ -48,6 +49,7 @@
],
"name":[
{
"fhir_comments":[" Peter James Chalmers, but called \"Jim\" "],
"use":"official",
"family":[
"Chalmers"

View File

@ -1,5 +1,4 @@
<Patient xmlns="http://hl7.org/fhir">
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://hl7.org/fhir ./fhir-single.xsd"> -->
<extension url="urn:patientext:att">
<valueAttachment>
<contentType value="aaaa"/>
@ -74,7 +73,6 @@
<telecom>
<use value="home"/>
<!-- home communication details aren't known -->
</telecom>
<telecom>
<system value="phone"/>
@ -82,7 +80,6 @@
<use value="work"/>
</telecom>
<!-- use FHIR code system for male / female -->
<gender>
<coding>
<system value="http://hl7.org/fhir/v3/AdministrativeGender"/>
@ -116,7 +113,6 @@
<name>
<family value="du">
<!-- the &quot;du&quot; part is a family name prefix (VV in iso 21090) -->
<extension url="http://hl7.org/fhir/Profile/iso-21090#qualifier">
<valueCode value="VV"/>
</extension>

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.not;
@ -64,55 +65,6 @@ public class JsonParserDstu2Test {
private static final FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserDstu2Test.class);
@Test
public void testNamespacePreservationEncode() throws Exception {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
//@formatter:on
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdDt("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newJsonParser().encodeResourceToString(new Binary());
assertEquals("{\"resourceType\":\"Binary\"}", output);
}
@Test
public void testNamespacePreservationParse() throws Exception {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>",encoded);
}
@Test
public void testEncodeAndParseExtensions() throws Exception {
@ -255,7 +207,7 @@ public class JsonParserDstu2Test {
assertEquals(new Tag("scheme1", "term1", "label1"), tagList.get(0));
assertEquals(new Tag("scheme2", "term2", "label2"), tagList.get(1));
}
@Test
public void testEncodeAndParseSecurityLabels() {
Patient p = new Patient();
@ -376,6 +328,22 @@ public class JsonParserDstu2Test {
//@formatter:on
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdDt("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newJsonParser().encodeResourceToString(new Binary());
assertEquals("{\"resourceType\":\"Binary\"}", output);
}
/**
* #158
*/
@ -490,6 +458,22 @@ public class JsonParserDstu2Test {
}
// see #241
@Test
public void testEncodeThenParseShouldNotAddSpuriousId() throws Exception {
Condition condition = new Condition().setVerificationStatus(ConditionVerificationStatusEnum.CONFIRMED);
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
ca.uhn.fhir.model.dstu2.resource.Bundle.Entry entry = new ca.uhn.fhir.model.dstu2.resource.Bundle.Entry();
entry.setFullUrl(IdDt.newRandomUuid());
entry.setResource(condition);
bundle.getEntry().add(entry);
IParser parser = ourCtx.newJsonParser();
String json = parser.encodeResourceToString(bundle);
ourLog.info(json);
bundle = (ca.uhn.fhir.model.dstu2.resource.Bundle) parser.parseResource(json);
assertThat(json, not(containsString("\"id\"")));
}
@Test
public void testEncodingNullExtension() {
Patient p = new Patient();
@ -527,6 +511,39 @@ public class JsonParserDstu2Test {
}
@Test
public void testNamespacePreservationEncode() throws Exception {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
//@formatter:on
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
@Test
public void testNamespacePreservationParse() throws Exception {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>",encoded);
}
@Test
public void testOmitResourceId() {
Patient p = new Patient();
@ -805,6 +822,75 @@ public class JsonParserDstu2Test {
assertThat(encoded, not(containsString("\"id\":\"180f219f-97a8-486d-99d9-ed631fe4fc57\"")));
}
@Test
public void testParseAndEncodeComments() throws IOException {
//@formatter:off
String input = "{\n" +
" \"resourceType\": \"Patient\",\n" +
" \"id\": \"pat1\",\n" +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
" \"div\": \"<div>\\n \\n <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\\n \\n </div>\"\n" +
" },\n" +
" \"identifier\": [\n" +
" {\n" +
" \"fhir_comments\":[\"identifier comment 1\",\"identifier comment 2\"],\n" +
" \"use\": \"usual\",\n" +
" \"_use\": {\n" +
" \"fhir_comments\":[\"use comment 1\",\"use comment 2\"]\n" +
" },\n" +
" \"type\": {\n" +
" \"coding\": [\n" +
" {\n" +
" \"system\": \"http://hl7.org/fhir/v2/0203\",\n" +
" \"code\": \"MR\"\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"system\": \"urn:oid:0.1.2.3.4.5.6.7\",\n" +
" \"value\": \"654321\"\n" +
" }\n" +
" ],\n" +
" \"active\": true" +
"}";
//@formatter:off
Patient res = ourCtx.newJsonParser().parseResource(Patient.class, input);
res.getFormatCommentsPre();
assertEquals("Patient/pat1", res.getId().getValue());
assertEquals("654321", res.getIdentifier().get(0).getValue());
assertEquals(true, res.getActive());
assertThat(res.getIdentifier().get(0).getFormatCommentsPre(), contains("identifier comment 1", "identifier comment 2"));
assertThat(res.getIdentifier().get(0).getUseElement().getFormatCommentsPre(), contains("use comment 1", "use comment 2"));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
//@formatter:off
assertThat(encoded, stringContainsInOrder(
"\"identifier\":[",
"{",
"\"fhir_comments\":",
"[",
"\"identifier comment 1\"",
",",
"\"identifier comment 2\"",
"]",
"\"use\":\"usual\",",
"\"_use\":{",
"\"fhir_comments\":",
"[",
"\"use comment 1\"",
",",
"\"use comment 2\"",
"]",
"},",
"\"type\""
));
//@formatter:off
}
@Test
public void testParseBundleWithBinary() {
Binary patient = new Binary();
@ -1037,20 +1123,4 @@ public class JsonParserDstu2Test {
ourLog.info(message);
Assert.assertThat(message, containsString("contained"));
}
// see #241
@Test
public void testEncodeThenParseShouldNotAddSpuriousId() throws Exception {
Condition condition = new Condition().setVerificationStatus(ConditionVerificationStatusEnum.CONFIRMED);
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
ca.uhn.fhir.model.dstu2.resource.Bundle.Entry entry = new ca.uhn.fhir.model.dstu2.resource.Bundle.Entry();
entry.setFullUrl(IdDt.newRandomUuid());
entry.setResource(condition);
bundle.getEntry().add(entry);
IParser parser = ourCtx.newJsonParser();
String json = parser.encodeResourceToString(bundle);
ourLog.info(json);
bundle = (ca.uhn.fhir.model.dstu2.resource.Bundle) parser.parseResource(json);
assertThat(json, not(containsString("\"id\"")));
}
}

View File

@ -17,6 +17,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
@ -96,6 +97,39 @@ public class XmlParserDstu2Test {
private static final FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
@Test
public void testBundleWithBinary() {
//@formatter:off
String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
" <meta/>\n" +
" <base value=\"http://localhost:52788\"/>\n" +
" <total value=\"1\"/>\n" +
" <link>\n" +
" <relation value=\"self\"/>\n" +
" <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
" </link>\n" +
" <entry>\n" +
" <resource>\n" +
" <Binary xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"1\"/>\n" +
" <meta/>\n" +
" <contentType value=\"text/plain\"/>\n" +
" <content value=\"AQIDBA==\"/>\n" +
" </Binary>\n" +
" </resource>\n" +
" </entry>\n" +
"</Bundle>";
//@formatter:on
Bundle b = ourCtx.newXmlParser().parseBundle(bundle);
assertEquals(1, b.getEntries().size());
Binary bin = (Binary) b.getEntries().get(0).getResource();
assertArrayEquals(new byte[] { 1, 2, 3, 4 }, bin.getContent());
}
@Test
public void testChoiceTypeWithProfiledType() {
//@formatter:off
@ -133,64 +167,6 @@ public class XmlParserDstu2Test {
assertEquals(MarkdownDt.class, par.getParameter().get(1).getValue().getClass());
}
@Test
public void testBundleWithBinary() {
//@formatter:off
String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
" <meta/>\n" +
" <base value=\"http://localhost:52788\"/>\n" +
" <total value=\"1\"/>\n" +
" <link>\n" +
" <relation value=\"self\"/>\n" +
" <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
" </link>\n" +
" <entry>\n" +
" <resource>\n" +
" <Binary xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"1\"/>\n" +
" <meta/>\n" +
" <contentType value=\"text/plain\"/>\n" +
" <content value=\"AQIDBA==\"/>\n" +
" </Binary>\n" +
" </resource>\n" +
" </entry>\n" +
"</Bundle>";
//@formatter:on
Bundle b = ourCtx.newXmlParser().parseBundle(bundle);
assertEquals(1, b.getEntries().size());
Binary bin = (Binary) b.getEntries().get(0).getResource();
assertArrayEquals(new byte[] { 1, 2, 3, 4 }, bin.getContent());
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newXmlParser().encodeResourceToString(new Binary());
assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"/>", output);
}
@Test
public void testParseInvalidTextualNumber() {
Observation obs = new Observation();
obs.setValue(new QuantityDt().setValue(1234));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs);
encoded = encoded.replace("1234", "\"1234\"");
ourLog.info(encoded);
ourCtx.newJsonParser().parseResource(encoded);
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdDt("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testContainedResourceInExtensionUndeclared() {
Patient p = new Patient();
@ -897,7 +873,23 @@ public class XmlParserDstu2Test {
assertThat(encoded, (containsString("BARFOO")));
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdDt("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newXmlParser().encodeResourceToString(new Binary());
assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"/>", output);
}
/**
* #158
*/
@ -914,7 +906,6 @@ public class XmlParserDstu2Test {
assertThat(encoded, not(containsString("tag")));
}
/**
* #158
*/
@ -932,7 +923,7 @@ public class XmlParserDstu2Test {
assertThat(encoded, containsString("scheme"));
assertThat(encoded, not(containsString("Label")));
}
@Test
public void testEncodeExtensionWithResourceContent() {
IParser parser = ourCtx.newXmlParser();
@ -1014,7 +1005,7 @@ public class XmlParserDstu2Test {
}
@Test
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
@ -1070,6 +1061,7 @@ public class XmlParserDstu2Test {
assertThat(encoded, not(containsString("maritalStatus")));
}
@Test
public void testEncodeSummary2() {
Patient patient = new Patient();
@ -1093,7 +1085,6 @@ public class XmlParserDstu2Test {
assertThat(encoded, not(containsString("maritalStatus")));
}
@Test
public void testEncodeWithEncodeElements() throws Exception {
String content = IOUtils.toString(XmlParserDstu2Test.class.getResourceAsStream("/bundle-example.xml"));
@ -1198,6 +1189,7 @@ public class XmlParserDstu2Test {
assertThat(enc, containsString("<given value=\"Shmoe\"><extension url=\"http://examples.com#givenext_parent\"><extension url=\"http://examples.com#givenext_child\"><valueString value=\"CHILD\"/></extension></extension></given>"));
}
@Test
public void testOmitResourceId() {
Patient p = new Patient();
@ -1208,7 +1200,7 @@ public class XmlParserDstu2Test {
assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), containsString("ABC"));
assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
}
@Test
public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(XmlParserDstu2Test.class.getResourceAsStream("/bundle-example.xml"));
@ -1281,7 +1273,108 @@ public class XmlParserDstu2Test {
}
@Test
public void testParseAndEncodeComments() throws IOException {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"pat1\"/>\n" +
" <text>\n" +
" <status value=\"generated\"/>\n" +
" <div xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
"\n" +
" <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\n" +
"\n" +
" </div>\n" +
" </text>\n" +
" <!--identifier comment 1-->\n" +
" <!--identifier comment 2-->\n" +
" <identifier>\n" +
" <!--use comment 1-->\n" +
" <!--use comment 2-->\n" +
" <use value=\"usual\"/>\n" +
" <type>\n" +
" <coding>\n" +
" <system value=\"http://hl7.org/fhir/v2/0203\"/>\n" +
" <code value=\"MR\"/>\n" +
" </coding>\n" +
" </type>\n" +
" <system value=\"urn:oid:0.1.2.3.4.5.6.7\"/>\n" +
" <value value=\"654321\"/>\n" +
" </identifier>\n" +
" <active value=\"true\"/>" +
"</Patient>";
//@formatter:off
Patient res = ourCtx.newXmlParser().parseResource(Patient.class, input);
res.getFormatCommentsPre();
assertEquals("Patient/pat1", res.getId().getValue());
assertEquals("654321", res.getIdentifier().get(0).getValue());
assertEquals(true, res.getActive());
assertThat(res.getIdentifier().get(0).getFormatCommentsPre(), contains("identifier comment 1", "identifier comment 2"));
assertThat(res.getIdentifier().get(0).getUseElement().getFormatCommentsPre(), contains("use comment 1", "use comment 2"));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
//@formatter:off
assertThat(encoded, stringContainsInOrder(
"\"identifier\":[",
"{",
"\"fhir_comments\":",
"[",
"\"identifier comment 1\"",
",",
"\"identifier comment 2\"",
"]",
"\"use\":\"usual\",",
"\"_use\":{",
"\"fhir_comments\":",
"[",
"\"use comment 1\"",
",",
"\"use comment 2\"",
"]",
"},",
"\"type\""
));
//@formatter:off
encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
//@formatter:off
assertThat(encoded, stringContainsInOrder(
"<Patient xmlns=\"http://hl7.org/fhir\">",
"<id value=\"pat1\"/>",
"<text>",
"<status value=\"generated\"/>",
"<div xmlns=\"http://www.w3.org/1999/xhtml\"> ",
"<p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p> ",
"</div>",
"</text>",
"<!--identifier comment 1-->",
"<!--identifier comment 2-->",
"<identifier>",
"<!--use comment 1-->",
"<!--use comment 2-->",
"<use value=\"usual\"/>",
"<type>",
"<coding>",
"<system value=\"http://hl7.org/fhir/v2/0203\"/>",
"<code value=\"MR\"/>",
"</coding>",
"</type>",
"<system value=\"urn:oid:0.1.2.3.4.5.6.7\"/>",
"<value value=\"654321\"/>",
"</identifier>",
"<active value=\"true\"/>",
"</Patient>"
));
//@formatter:off
}
@Test
public void testParseAndEncodeExtensionOnResourceReference() {
//@formatter:off
@ -1509,7 +1602,8 @@ public class XmlParserDstu2Test {
ourLog.info("Actual : {}", output);
assertEquals(input, output);
}
@Test
public void testParseBundleNewWithPlaceholderIds() {
//@formatter:off
@ -1768,6 +1862,16 @@ public class XmlParserDstu2Test {
}
@Test
public void testParseInvalidTextualNumber() {
Observation obs = new Observation();
obs.setValue(new QuantityDt().setValue(1234));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs);
encoded = encoded.replace("1234", "\"1234\"");
ourLog.info(encoded);
ourCtx.newJsonParser().parseResource(encoded);
}
/**
* See #216
*/

View File

@ -1081,6 +1081,21 @@ public class GenericClientDstu2Test {
public boolean isEmpty() {
return false;
}
@Override
public boolean hasFormatComment() {
return false;
}
@Override
public List<String> getFormatCommentsPre() {
return null;
}
@Override
public List<String> getFormatCommentsPost() {
return null;
}
};
//@formatter:off

View File

@ -37,9 +37,6 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.util.PortUtil;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class ValidateDstu2Test {
private static CloseableHttpClient ourClient;
private static EncodingEnum ourLastEncoding;

View File

@ -68,16 +68,19 @@ private Map<String, Object> userData;
return (Integer) getUserData(name);
}
@Override
public boolean hasFormatComment() {
return (formatCommentsPre != null && !formatCommentsPre.isEmpty()) || (formatCommentsPost != null && !formatCommentsPost.isEmpty());
}
@Override
public List<String> getFormatCommentsPre() {
if (formatCommentsPre == null)
formatCommentsPre = new ArrayList<String>();
return formatCommentsPre;
}
@Override
public List<String> getFormatCommentsPost() {
if (formatCommentsPost == null)
formatCommentsPost = new ArrayList<String>();

View File

@ -35,6 +35,8 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseXhtml;
import ca.uhn.fhir.util.CoverageIgnore;
@ca.uhn.fhir.model.api.annotation.DatatypeDef(name="xhtml")
public class XhtmlNode implements IBaseXhtml {
@ -360,4 +362,31 @@ public XhtmlNode setValue(String theValue) throws IllegalArgumentException {
return this;
}
/**
* Returns false
*/
@Override
@CoverageIgnore
public boolean hasFormatComment() {
return false;
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPre() {
throw new UnsupportedOperationException();
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPost() {
throw new UnsupportedOperationException();
}
}

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
@ -10,41 +11,44 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.util.IO;
import org.hamcrest.Matchers;
import org.hl7.fhir.dstu3.model.Binary;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.Condition;
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
import org.hl7.fhir.dstu3.model.Conformance;
import org.hl7.fhir.dstu3.model.DateTimeType;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.DecimalType;
import org.hl7.fhir.dstu3.model.DiagnosticReport;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.HumanName;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
import org.hl7.fhir.dstu3.model.Medication;
import org.hl7.fhir.dstu3.model.MedicationOrder;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.Specimen;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.junit.After;
import org.junit.Assert;
@ -52,7 +56,6 @@ import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.server.Constants;
import net.sf.json.JSON;
@ -63,128 +66,10 @@ public class JsonParserDstu3Test {
private static final FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserDstu3Test.class);
@Test
public void testEncodeParametersWithId() {
Parameters reqParms = new Parameters();
IdType patient = new IdType(1);
reqParms.addParameter().setName("patient").setValue(patient);
String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(reqParms);
ourLog.info(enc);
assertThat(enc, containsString("\"valueId\":\"1\""));
}
@Test
public void testEncodeWithNarrative() {
Patient p = new Patient();
p.addName().addFamily("Smith").addGiven("John");
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
String output = ourCtx.newJsonParser().encodeResourceToString(p);
ourLog.info(output);
assertThat(output, containsString("\"text\":{\"status\":\"generated\",\"div\":\"<div><div class=\\\"hapiHeaderText\\\"> John <b>SMITH </b></div>"));
}
@After
public void after() {
ourCtx.setNarrativeGenerator(null);
}
// FIXME: this should pass
@Test
@Ignore
public void testNamespacePreservationEncode() throws Exception {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
//@formatter:on
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdType("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testExponentDoesntGetEncodedAsSuch() {
Observation obs = new Observation();
obs.setValue(new Quantity().setValue(new BigDecimal("0.000000000000000100")));
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
}
@Test
public void testExponentParseWorks() {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
assertEquals("0.0000000000000001", ((Quantity)obs.getValue()).getValueElement().getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}", str);
}
@Test
public void testParseWithPrecision() {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
DecimalType valueElement = ((Quantity)obs.getValue()).getValueElement();
assertEquals("0.000000000000000100", valueElement.getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newJsonParser().encodeResourceToString(new Binary());
assertEquals("{\"resourceType\":\"Binary\"}", output);
}
//TODO: this should pass
@Test
@Ignore
public void testNamespacePreservationParse() throws Exception {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
XhtmlNode div = parsed.getText().getDiv();
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>",encoded);
}
@Test
public void testEncodeAndParseExtensions() throws Exception {
@ -229,10 +114,8 @@ public class JsonParserDstu3Test {
assertThat(enc, Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}",
"{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}"));
assertThat(enc, Matchers.stringContainsInOrder("\"modifierExtension\":[" + "{" + "\"url\":\"http://example.com/extensions#modext\"," + "\"valueDate\":\"1995-01-02\"" + "}" + "],"));
assertThat(enc,
containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{"
+ "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}"
+ "]" + "}"));
assertThat(enc, containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{"
+ "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}" + "]" + "}"));
/*
* Now parse this back
@ -271,7 +154,7 @@ public class JsonParserDstu3Test {
assertEquals("CHILD", ((StringType) given2ext2.getValue()).getValue());
}
@Test
public void testEncodeAndParseMetaProfileAndTags() {
Patient p = new Patient();
@ -323,7 +206,7 @@ public class JsonParserDstu3Test {
//@formatter:on
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc);
List<UriType> gotLabels = parsed.getMeta().getProfile();
assertEquals(2, gotLabels.size());
UriType label = (UriType) gotLabels.get(0);
@ -428,8 +311,21 @@ public class JsonParserDstu3Test {
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdType("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newJsonParser().encodeResourceToString(new Binary());
assertEquals("{\"resourceType\":\"Binary\"}", output);
}
/**
* #158
@ -484,6 +380,18 @@ public class JsonParserDstu3Test {
assertThat(encoded, containsString("maritalStatus"));
}
@Test
public void testEncodeParametersWithId() {
Parameters reqParms = new Parameters();
IdType patient = new IdType(1);
reqParms.addParameter().setName("patient").setValue(patient);
String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(reqParms);
ourLog.info(enc);
assertThat(enc, containsString("\"valueId\":\"1\""));
}
@Test
public void testEncodeSummary() {
Patient patient = new Patient();
@ -494,7 +402,7 @@ public class JsonParserDstu3Test {
patient.getMaritalStatus().addCoding().setCode("D");
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).setSummaryMode(true).encodeResourceToString(patient);
ourLog.info(encoded);
@ -519,8 +427,7 @@ public class JsonParserDstu3Test {
ourLog.info(encoded);
assertThat(encoded, containsString("Patient"));
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"",
"\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\""));
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"", "\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\""));
assertThat(encoded, not(containsString("THE DIV")));
assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus")));
@ -539,11 +446,39 @@ public class JsonParserDstu3Test {
String enc = ourCtx.newJsonParser().encodeResourceToString(pt);
ourLog.info(enc);
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}",
enc);
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}", enc);
}
// see #241
@Test
public void testEncodeThenParseShouldNotAddSpuriousId() throws Exception {
Condition condition = new Condition().setVerificationStatus(ConditionVerificationStatus.CONFIRMED);
Bundle bundle = new Bundle();
BundleEntryComponent entry = new Bundle.BundleEntryComponent();
entry.setIdElement(IdType.newRandomUuid());
entry.setResource(condition);
bundle.getEntry().add(entry);
IParser parser = ourCtx.newJsonParser();
String json = parser.encodeResourceToString(bundle);
ourLog.info(json);
bundle = (Bundle) parser.parseResource(json);
assertThat(json, not(containsString("\"id\"")));
}
@Test
public void testEncodeWithNarrative() {
Patient p = new Patient();
p.addName().addFamily("Smith").addGiven("John");
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
String output = ourCtx.newJsonParser().encodeResourceToString(p);
ourLog.info(output);
assertThat(output, containsString("\"text\":{\"status\":\"generated\",\"div\":\"<div><div class=\\\"hapiHeaderText\\\"> John <b>SMITH </b></div>"));
}
@Test
public void testEncodingNullExtension() {
Patient p = new Patient();
@ -565,6 +500,29 @@ public class JsonParserDstu3Test {
}
@Test
public void testExponentDoesntGetEncodedAsSuch() {
Observation obs = new Observation();
obs.setValue(new Quantity().setValue(new BigDecimal("0.000000000000000100")));
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
}
@Test
public void testExponentParseWorks() {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
assertEquals("0.0000000000000001", ((Quantity) obs.getValue()).getValueElement().getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}", str);
}
/**
* #65
*/
@ -581,6 +539,44 @@ public class JsonParserDstu3Test {
}
// FIXME: this should pass
@Test
@Ignore
public void testNamespacePreservationEncode() throws Exception {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
//@formatter:on
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
// TODO: this should pass
@Test
@Ignore
public void testNamespacePreservationParse() throws Exception {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
XhtmlNode div = parsed.getText().getDiv();
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>", encoded);
}
@Test
public void testOmitResourceId() {
Patient p = new Patient();
@ -592,7 +588,8 @@ public class JsonParserDstu3Test {
assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
}
@Test @Ignore
@Test
@Ignore
public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(JsonParserDstu3Test.class.getResourceAsStream("/bundle-example.json"));
@ -617,8 +614,8 @@ public class JsonParserDstu3Test {
Medication m = (Medication) parsed.getEntry().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId());
assertSame(((Reference)p.getMedication()).getResource(), m);
assertSame(((Reference) p.getMedication()).getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded);
@ -640,7 +637,8 @@ public class JsonParserDstu3Test {
/**
* Test for #146
*/
@Test @Ignore
@Test
@Ignore
public void testParseAndEncodeBundleFromXmlToJson() throws Exception {
String content = IOUtils.toString(JsonParserDstu3Test.class.getResourceAsStream("/bundle-example2.xml"));
@ -664,7 +662,8 @@ public class JsonParserDstu3Test {
assertThat(reencoded, containsString("contained"));
}
@Test @Ignore
@Test
@Ignore
public void testParseAndEncodeBundleNewStyle() throws Exception {
String content = IOUtils.toString(JsonParserDstu3Test.class.getResourceAsStream("/bundle-example.json"));
@ -686,11 +685,11 @@ public class JsonParserDstu3Test {
assertEquals("Patient/347", p.getPatient().getReference());
assertEquals("2014-08-16T05:31:17Z", p.getMeta().getLastUpdatedElement().getValueAsString());
assertEquals("http://example.com/base/MedicationOrder/3123/_history/1", p.getId());
// assertEquals("3123", p.getId());
// assertEquals("3123", p.getId());
Medication m = (Medication) parsed.getEntry().get(1).getResource();
assertEquals("http://example.com/base/Medication/example", m.getId());
assertSame(((Reference)p.getMedication()).getResource(), m);
assertSame(((Reference) p.getMedication()).getResource(), m);
String reencoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(reencoded);
@ -710,7 +709,6 @@ public class JsonParserDstu3Test {
}
@Test
public void testParseAndEncodeBundleWithUuidBase() {
//@formatter:off
@ -793,6 +791,75 @@ public class JsonParserDstu3Test {
assertThat(encoded, not(containsString("\"id\":\"180f219f-97a8-486d-99d9-ed631fe4fc57\"")));
}
@Test
public void testParseAndEncodeComments() throws IOException {
//@formatter:off
String input = "{\n" +
" \"resourceType\": \"Patient\",\n" +
" \"id\": \"pat1\",\n" +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
" \"div\": \"<div>\\n \\n <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\\n \\n </div>\"\n" +
" },\n" +
" \"identifier\": [\n" +
" {\n" +
" \"fhir_comments\":[\"identifier comment 1\",\"identifier comment 2\"],\n" +
" \"use\": \"usual\",\n" +
" \"_use\": {\n" +
" \"fhir_comments\":[\"use comment 1\",\"use comment 2\"]\n" +
" },\n" +
" \"type\": {\n" +
" \"coding\": [\n" +
" {\n" +
" \"system\": \"http://hl7.org/fhir/v2/0203\",\n" +
" \"code\": \"MR\"\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"system\": \"urn:oid:0.1.2.3.4.5.6.7\",\n" +
" \"value\": \"654321\"\n" +
" }\n" +
" ],\n" +
" \"active\": true" +
"}";
//@formatter:off
Patient res = ourCtx.newJsonParser().parseResource(Patient.class, input);
res.getFormatCommentsPre();
assertEquals("Patient/pat1", res.getId());
assertEquals("654321", res.getIdentifier().get(0).getValue());
assertEquals(true, res.getActive());
assertThat(res.getIdentifier().get(0).getFormatCommentsPre(), contains("identifier comment 1", "identifier comment 2"));
assertThat(res.getIdentifier().get(0).getUseElement().getFormatCommentsPre(), contains("use comment 1", "use comment 2"));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
//@formatter:off
assertThat(encoded, stringContainsInOrder(
"\"identifier\":[",
"{",
"\"fhir_comments\":",
"[",
"\"identifier comment 1\"",
",",
"\"identifier comment 2\"",
"]",
"\"use\":\"usual\",",
"\"_use\":{",
"\"fhir_comments\":",
"[",
"\"use comment 1\"",
",",
"\"use comment 2\"",
"]",
"},",
"\"type\""
));
//@formatter:off
}
@Test
public void testParseBundleWithBinary() {
Binary patient = new Binary();
@ -801,7 +868,7 @@ public class JsonParserDstu3Test {
patient.setContent(new byte[] { 1, 2, 3, 4 });
String val = ourCtx.newJsonParser().encodeResourceToString(patient);
String expected = "{\"resourceType\":\"Binary\",\"id\":\"11\",\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}";
ourLog.info("Expected: {}", expected);
ourLog.info("Actual : {}", val);
@ -811,7 +878,8 @@ public class JsonParserDstu3Test {
/**
* see #144 and #146
*/
@Test @Ignore
@Test
@Ignore
public void testParseContained() {
FhirContext c = FhirContext.forDstu2();
@ -908,7 +976,6 @@ public class JsonParserDstu3Test {
}
/**
* See #163
*/
@ -955,7 +1022,21 @@ public class JsonParserDstu3Test {
}
}
@Test @Ignore
@Test
public void testParseWithPrecision() {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
assertEquals("0.000000000000000100", valueElement.getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
}
@Test
@Ignore
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json"));
try {
@ -1011,20 +1092,4 @@ public class JsonParserDstu3Test {
ourLog.info(message);
Assert.assertThat(message, containsString("contained"));
}
// see #241
@Test
public void testEncodeThenParseShouldNotAddSpuriousId() throws Exception {
Condition condition = new Condition().setVerificationStatus(ConditionVerificationStatus.CONFIRMED);
Bundle bundle = new Bundle();
BundleEntryComponent entry = new Bundle.BundleEntryComponent();
entry.setIdElement(IdType.newRandomUuid());
entry.setResource(condition);
bundle.getEntry().add(entry);
IParser parser = ourCtx.newJsonParser();
String json = parser.encodeResourceToString(bundle);
ourLog.info(json);
bundle = (Bundle) parser.parseResource(json);
assertThat(json, not(containsString("\"id\"")));
}
}

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
@ -16,6 +17,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
@ -92,6 +94,101 @@ public class XmlParserDstu3Test {
private static final FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu3Test.class);
@After
public void after() {
ourCtx.setNarrativeGenerator(null);
}
@Test
public void testParseAndEncodeCommentsOnExtensions() {
//@formatter:off
String input =
"<Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <!-- comment 1 -->\n" +
" <id value=\"someid\"/>\n" +
" <!-- comment 2 -->\n" +
" <extension url=\"urn:patientext:att\">\n" +
" <!-- comment 3 -->\n" +
" <valueAttachment>\n" +
" <!-- comment 4 -->\n" +
" <contentType value=\"aaaa\"/>\n" +
" <data value=\"AAAA\"/>\n" +
" <!-- comment 5 -->\n" +
" </valueAttachment>\n" +
" <!-- comment 6 -->\n" +
" </extension>\n" +
" <!-- comment 7 -->\n" +
"</Patient>";
Patient pat = ourCtx.newXmlParser().parseResource(Patient.class, input);
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(pat);
ourLog.info(output);
assertThat(output, stringContainsInOrder(
"<Patient xmlns=\"http://hl7.org/fhir\">",
" <!-- comment 1 -->",
" <id value=\"someid\"/>",
" <!-- comment 2 -->",
" <extension url=\"urn:patientext:att\">",
" <!-- comment 3 -->",
" <valueAttachment>",
" <!-- comment 4 -->",
" <contentType value=\"aaaa\"/>",
" <data value=\"AAAA\"/>",
" <!-- comment 5 -->",
" </valueAttachment>",
" <!-- comment 6 -->",
" </extension>",
" <!-- comment 7 -->",
"</Patient>"
));
output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(pat);
ourLog.info(output);
assertThat(output, stringContainsInOrder(
"{",
" \"resourceType\":\"Patient\",",
" \"id\":\"someid\",",
" \"_id\":{",
" \"fhir_comments\":[",
" \" comment 1 \"",
" ]",
" },",
" \"extension\":[",
" {",
" \"fhir_comments\":[",
" \" comment 2 \",",
" \" comment 7 \"",
" ],",
" \"url\":\"urn:patientext:att\",",
" \"valueAttachment\":{",
" \"fhir_comments\":[",
" \" comment 3 \",",
" \" comment 6 \"",
" ],",
" \"contentType\":\"aaaa\",",
" \"_contentType\":{",
" \"fhir_comments\":[",
" \" comment 4 \"",
" ]",
" },",
" \"data\":\"AAAA\",",
" \"_data\":{",
" \"fhir_comments\":[",
" \" comment 5 \"",
" ]",
" }",
" }",
" }",
" ]",
"}"
));
//@formatter:on
}
@Test
public void testBundleWithBinary() {
//@formatter:off
@ -124,52 +221,6 @@ public class XmlParserDstu3Test {
}
@Test
public void testEncodeWithNarrative() {
Patient p = new Patient();
p.addName().addFamily("Smith").addGiven("John");
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
String output = ourCtx.newXmlParser().encodeResourceToString(p);
ourLog.info(output);
assertThat(output, containsString("<text><status value=\"generated\"/><div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> John <b>SMITH </b>"));
}
@After
public void after() {
ourCtx.setNarrativeGenerator(null);
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newXmlParser().encodeResourceToString(new Binary());
assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"/>", output);
}
@Test
public void testParseInvalidTextualNumber() {
Observation obs = new Observation();
obs.setValue(new Quantity().setValue(1234));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs);
encoded = encoded.replace("1234", "\"1234\"");
ourLog.info(encoded);
ourCtx.newJsonParser().parseResource(encoded);
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdType("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testContainedResourceInExtensionUndeclared() {
Patient p = new Patient();
@ -191,7 +242,7 @@ public class XmlParserDstu3Test {
o = (Organization) rr.getResource();
assertEquals("ORG", o.getName());
}
@Test
public void testDuration() {
Encounter enc = new Encounter();
@ -205,7 +256,7 @@ public class XmlParserDstu3Test {
assertThat(str, not(containsString("meta")));
assertThat(str, containsString("<length><value value=\"123\"/><unit value=\"day\"/></length>"));
}
@Test
public void testEncodeAndParseContained() {
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
@ -275,6 +326,26 @@ public class XmlParserDstu3Test {
}
@Test
public void testEncodeAndParseExtensionOnCode() {
Organization o = new Organization();
o.setName("ORG");
o.addExtension(new Extension("urn:foo", new CodeType("acode")));
String str = ourCtx.newXmlParser().encodeResourceToString(o);
ourLog.info(str);
assertThat(str, containsString("<valueCode value=\"acode\"/>"));
o = ourCtx.newXmlParser().parseResource(Organization.class, str);
List<Extension> exts = o.getExtensionsByUrl("urn:foo");
assertEquals(1, exts.size());
CodeType code = (CodeType) exts.get(0).getValue();
assertEquals("acode", code.getValue());
}
@Test
public void testEncodeAndParseExtensionOnReference() {
DataElement de = new DataElement();
@ -299,26 +370,8 @@ public class XmlParserDstu3Test {
assertEquals("ORG", o.getName());
}
@Test
public void testEncodeAndParseExtensionOnCode() {
Organization o = new Organization();
o.setName("ORG");
o.addExtension(new Extension("urn:foo", new CodeType("acode")));
String str = ourCtx.newXmlParser().encodeResourceToString(o);
ourLog.info(str);
assertThat(str, containsString("<valueCode value=\"acode\"/>"));
o = ourCtx.newXmlParser().parseResource(Organization.class, str);
List<Extension> exts = o.getExtensionsByUrl("urn:foo");
assertEquals(1, exts.size());
CodeType code = (CodeType) exts.get(0).getValue();
assertEquals("acode", code.getValue());
}
@Test
public void testEncodeAndParseExtensions() throws Exception {
@ -694,8 +747,6 @@ public class XmlParserDstu3Test {
assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"><content value=\"AQIDBA==\"/></Binary>", output);
}
@Test
public void testEncodeBundleWithContained() {
DiagnosticReport rpt = new DiagnosticReport();
@ -842,7 +893,25 @@ public class XmlParserDstu3Test {
assertThat(encoded, (containsString("BARFOO")));
}
@Test
public void testEncodeDoesntIncludeUuidId() {
Patient p = new Patient();
p.setId(new IdType("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
p.addIdentifier().setSystem("ACME");
String actual = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(actual, not(containsString("78ef6f64c2f2")));
}
@Test
public void testEncodeEmptyBinary() {
String output = ourCtx.newXmlParser().encodeResourceToString(new Binary());
assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"/>", output);
}
/**
* #158
*/
@ -859,7 +928,6 @@ public class XmlParserDstu3Test {
assertThat(encoded, not(containsString("tag")));
}
/**
* #158
*/
@ -898,7 +966,6 @@ public class XmlParserDstu3Test {
assertEquals("Organization/123", ref.getReference());
}
@Test
public void testEncodeNarrativeSuppressed() {
@ -920,6 +987,7 @@ public class XmlParserDstu3Test {
assertThat(encoded, containsString("maritalStatus"));
}
@Test
public void testEncodeNonContained() {
// Create an organization
@ -960,7 +1028,6 @@ public class XmlParserDstu3Test {
}
@Test
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
@ -998,6 +1065,7 @@ public class XmlParserDstu3Test {
assertThat(str, containsString("<reference value=\"Observation/phitcc_obs_bp_dia\"/>"));
}
@Test
public void testEncodeSummary() {
Patient patient = new Patient();
@ -1037,7 +1105,7 @@ public class XmlParserDstu3Test {
assertThat(encoded, not(containsString("maritalStatus")));
}
@Test @Ignore
public void testEncodeWithEncodeElements() throws Exception {
String content = IOUtils.toString(XmlParserDstu3Test.class.getResourceAsStream("/bundle-example.xml"));
@ -1088,6 +1156,19 @@ public class XmlParserDstu3Test {
}
@Test
public void testEncodeWithNarrative() {
Patient p = new Patient();
p.addName().addFamily("Smith").addGiven("John");
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
String output = ourCtx.newXmlParser().encodeResourceToString(p);
ourLog.info(output);
assertThat(output, containsString("<text><status value=\"generated\"/><div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> John <b>SMITH </b>"));
}
@Test
public void testMoreExtensions() throws Exception {
@ -1142,6 +1223,7 @@ public class XmlParserDstu3Test {
assertThat(enc, containsString("<given value=\"Shmoe\"><extension url=\"http://examples.com#givenext_parent\"><extension url=\"http://examples.com#givenext_child\"><valueString value=\"CHILD\"/></extension></extension></given>"));
}
@Test
public void testOmitResourceId() {
Patient p = new Patient();
@ -1152,7 +1234,7 @@ public class XmlParserDstu3Test {
assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), containsString("ABC"));
assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
}
@Test @Ignore
public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(XmlParserDstu3Test.class.getResourceAsStream("/bundle-example.xml"));
@ -1225,7 +1307,112 @@ public class XmlParserDstu3Test {
}
@Test
public void testParseAndEncodeComments() throws IOException {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <!--pre resource comment-->" +
" <id value=\"pat1\"/>\n" +
" <text>\n" +
" <status value=\"generated\"/>\n" +
" <div xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
"\n" +
" <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\n" +
"\n" +
" </div>\n" +
" </text>\n" +
" <!--identifier comment 1-->\n" +
" <!--identifier comment 2-->\n" +
" <identifier>\n" +
" <!--use comment 1-->\n" +
" <!--use comment 2-->\n" +
" <use value=\"usual\"/>\n" +
" <type>\n" +
" <coding>\n" +
" <system value=\"http://hl7.org/fhir/v2/0203\"/>\n" +
" <code value=\"MR\"/>\n" +
" </coding>\n" +
" </type>\n" +
" <system value=\"urn:oid:0.1.2.3.4.5.6.7\"/>\n" +
" <value value=\"654321\"/>\n" +
" </identifier>\n" +
" <active value=\"true\"/>" +
" <!--post resource comment-->" +
"</Patient>";
//@formatter:off
Patient res = ourCtx.newXmlParser().parseResource(Patient.class, input);
res.getFormatCommentsPre();
assertEquals("Patient/pat1", res.getId());
assertEquals("654321", res.getIdentifier().get(0).getValue());
assertEquals(true, res.getActive());
assertThat(res.getIdElement().getFormatCommentsPre(), contains("pre resource comment"));
assertThat(res.getIdentifier().get(0).getFormatCommentsPre(), contains("identifier comment 1", "identifier comment 2"));
assertThat(res.getIdentifier().get(0).getUseElement().getFormatCommentsPre(), contains("use comment 1", "use comment 2"));
assertThat(res.getActiveElement().getFormatCommentsPost(), contains("post resource comment"));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
//@formatter:off
assertThat(encoded, stringContainsInOrder(
"\"identifier\":[",
"{",
"\"fhir_comments\":",
"[",
"\"identifier comment 1\"",
",",
"\"identifier comment 2\"",
"]",
"\"use\":\"usual\",",
"\"_use\":{",
"\"fhir_comments\":",
"[",
"\"use comment 1\"",
",",
"\"use comment 2\"",
"]",
"},",
"\"type\""
));
//@formatter:off
encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
//@formatter:off
assertThat(encoded, stringContainsInOrder(
"<Patient xmlns=\"http://hl7.org/fhir\">",
"<id value=\"pat1\"/>",
"<text>",
"<status value=\"generated\"/>",
"<div xmlns=\"http://www.w3.org/1999/xhtml\"> ",
"<p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p> ",
"</div>",
"</text>",
" <!--identifier comment 1-->\n",
" <!--identifier comment 2-->",
"<identifier>",
"<!--use comment 1-->",
"<!--use comment 2-->",
"<use value=\"usual\"/>",
"<type>",
"<coding>",
"<system value=\"http://hl7.org/fhir/v2/0203\"/>",
"<code value=\"MR\"/>",
"</coding>",
"</type>",
"<system value=\"urn:oid:0.1.2.3.4.5.6.7\"/>",
"<value value=\"654321\"/>",
"</identifier>",
"<active value=\"true\"/>",
"</Patient>"
));
//@formatter:off
}
@Test
public void testParseAndEncodeExtensionOnReference() {
//@formatter:off
@ -1461,7 +1648,8 @@ public class XmlParserDstu3Test {
ourLog.info("Actual : {}", output);
assertEquals(input, output);
}
@Test
public void testParseBundleNewWithPlaceholderIds() {
//@formatter:off
@ -1706,6 +1894,16 @@ public class XmlParserDstu3Test {
assertNotNull(((Reference) actual.getContent().get(0).getP()).getResource());
}
@Test
public void testParseInvalidTextualNumber() {
Observation obs = new Observation();
obs.setValue(new Quantity().setValue(1234));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs);
encoded = encoded.replace("1234", "\"1234\"");
ourLog.info(encoded);
ourCtx.newJsonParser().parseResource(encoded);
}
/**
* See #216
*/

View File

@ -0,0 +1,136 @@
{
"resourceType": "Specimen",
"id": "101",
"text": {
"fhir_comments": [
" text>\n <status value=\"generated\" />\n <div xmlns=\"http://www.w3.org/1999/xhtml\">[Put rendering here]</div>\n </text> "
],
"status": "generated",
"div": "<div><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 101</p><p><b>contained</b>: </p><p><b>identifier</b>: 23234352356</p><p><b>status</b>: available</p><p><b>type</b>: Venous blood specimen <span>(Details : {SNOMED CT code '122555007' = '122555007', given as 'Venous blood specimen'})</span></p><p><b>subject</b>: <a>Peter Patient</a></p><p><b>accessionIdentifier</b>: X352356</p><p><b>receivedTime</b>: Mar 4, 2011 2:03:00 AM</p><h3>Collections</h3><table><tr><td>-</td><td><b>Collector</b></td><td><b>Comment</b></td><td><b>Collected[x]</b></td><td><b>Quantity</b></td><td><b>Method</b></td></tr><tr><td>*</td><td><a>Practitioner/example</a></td><td>Specimen is grossly lipemic</td><td>May 30, 2011 2:15:00 AM</td><td>6 mL</td><td>Line, Venous <span>(Details : {http://hl7.org/fhir/v2/0488 code 'LNV' = 'Line, Venous)</span></td></tr></table><h3>Containers</h3><table><tr><td>-</td><td><b>Identifier</b></td><td><b>Description</b></td><td><b>Type</b></td><td><b>Capacity</b></td><td><b>SpecimenQuantity</b></td><td><b>Additive[x]</b></td></tr><tr><td>*</td><td>48736-15394-75465</td><td>Green Gel tube</td><td>Vacutainer <span>(Details )</span></td><td>10 mL</td><td>6 mL</td><td>id: hep; Lithium/Li Heparin <span>(Details : {http://hl7.org/fhir/v3/EntityCode code 'HEPL' = 'Lithium/Li Heparin)</span></td></tr></table></div>"
},
"contained": [
{
"resourceType": "Substance",
"id": "hep",
"code": {
"coding": [
{
"system": "http://hl7.org/fhir/v3/EntityCode",
"code": "HEPL"
}
]
}
}
],
"identifier": [
{
"fhir_comments": [
" a specimen identifier - e.g. assigned when the specimen was taken\n this is often not done "
],
"system": "http://ehr.acme.org/identifiers/collections",
"value": "23234352356"
}
],
"status": "available",
"_status": {
"fhir_comments": [
" status is really about the specimen availability and includes the concepts available - The physical specimen is present and in good condition entered-in-error - The specimen was entered in error and therefore nullified. unavailable - There is no physical specimen because it is either lost, destroyed or consumed. unsatisfactory - The specimen cannot be used because of either a quality issue such as a broken container, contamination, or too old. "
]
},
"type": {
"fhir_comments": [
" \n Type is a loosely defined field because there is such a lot of variation in how it is used.\n The principal variation is how much information that could be represented elsewhere is also \n represented here. For instance, here's some possible types:\n lithium heparin plasma (+ .container.additive) (e.g. SNOMED CT 446272009)\n transfusion bag of blood (+ container.type) \n Peritoneal lavage (+ collection.bodySite)\n If the type includes other fields, it would be normal not to populate the other fields\n\n Note that this practice is so widespread that it's pointless to try and stop it "
],
"coding": [
{
"system": "http://snomed.info/sct",
"code": "122555007",
"display": "Venous blood specimen"
}
]
},
"subject": {
"reference": "Patient/example",
"display": "Peter Patient"
},
"accessionIdentifier": {
"fhir_comments": [
" accession identifier - e.g. assigned by the labaratory when it is received.\n This is common, unlike specimen identifier "
],
"system": "http://lab.acme.org/specimens/2011",
"value": "X352356"
},
"receivedTime": "2011-03-04T07:03:00Z",
"collection": {
"collector": {
"reference": "Practitioner/example"
},
"comment": [
"Specimen is grossly lipemic"
],
"collectedDateTime": "2011-05-30T06:15:00Z",
"_collectedDateTime": {
"fhir_comments": [
" the time of collection is usually required. Usually a point in time, but can be a period \n (collectedPeriod) if it's a timed collection (e.g. a 24 hour urine) "
]
},
"quantity": {
"fhir_comments": [
" e.g. full "
],
"value": 6,
"unit": "mL"
},
"method": {
"fhir_comments": [
" method is usually implied by type "
],
"coding": [
{
"system": "http://hl7.org/fhir/v2/0488",
"code": "LNV"
}
]
}
},
"container": [
{
"identifier": [
{
"fhir_comments": [
" \n the container identifier is not the same as the specimen identifier\n usually, it is pre-printed/implanted etc.on the container prior to \n use. It might a RFID in the container, or it might be a UDI \n (http://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/UniqueDeviceIdentification/) \n "
],
"value": "48736-15394-75465",
"_value": {
"fhir_comments": [
" this is a serial number off the tube - there's no context such as a system "
]
}
}
],
"description": "Green Gel tube",
"type": {
"text": "Vacutainer",
"_text": {
"fhir_comments": [
" again, this might easily be used to cover additives and capacity as well "
]
}
},
"capacity": {
"value": 10,
"unit": "mL"
},
"specimenQuantity": {
"fhir_comments": [
" if there's only one container, then this value is the same \n as .collection.quantity (usually). This is for when there is more\n than one container "
],
"value": 6,
"unit": "mL"
},
"additiveReference": {
"reference": "#hep"
}
}
]
}

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?><Specimen xmlns="http://hl7.org/fhir">
<id value="101"/>
<!-- text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml">[Put rendering here]</div>
</text> -->
<text><status value="generated"/><div xmlns="http://www.w3.org/1999/xhtml"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 101</p><p><b>contained</b>: </p><p><b>identifier</b>: 23234352356</p><p><b>status</b>: available</p><p><b>type</b>: Venous blood specimen <span>(Details : {SNOMED CT code &#39;122555007&#39; = &#39;122555007&#39;, given as &#39;Venous blood specimen&#39;})</span></p><p><b>subject</b>: <a>Peter Patient</a></p><p><b>accessionIdentifier</b>: X352356</p><p><b>receivedTime</b>: Mar 4, 2011 2:03:00 AM</p><h3>Collections</h3><table><tr><td>-</td><td><b>Collector</b></td><td><b>Comment</b></td><td><b>Collected[x]</b></td><td><b>Quantity</b></td><td><b>Method</b></td></tr><tr><td>*</td><td><a>Practitioner/example</a></td><td>Specimen is grossly lipemic</td><td>May 30, 2011 2:15:00 AM</td><td>6 mL</td><td>Line, Venous <span>(Details : {http://hl7.org/fhir/v2/0488 code &#39;LNV&#39; = &#39;Line, Venous)</span></td></tr></table><h3>Containers</h3><table><tr><td>-</td><td><b>Identifier</b></td><td><b>Description</b></td><td><b>Type</b></td><td><b>Capacity</b></td><td><b>SpecimenQuantity</b></td><td><b>Additive[x]</b></td></tr><tr><td>*</td><td>48736-15394-75465</td><td>Green Gel tube</td><td>Vacutainer <span>(Details )</span></td><td>10 mL</td><td>6 mL</td><td>id: hep; Lithium/Li Heparin <span>(Details : {http://hl7.org/fhir/v3/EntityCode code &#39;HEPL&#39; = &#39;Lithium/Li Heparin)</span></td></tr></table></div></text><contained>
<Substance>
<id value="hep"/>
<code>
<coding>
<system value="http://hl7.org/fhir/v3/EntityCode"/>
<code value="HEPL"/>
</coding>
</code>
</Substance>
</contained>
<!-- a specimen identifier - e.g. assigned when the specimen was taken
this is often not done -->
<identifier>
<system value="http://ehr.acme.org/identifiers/collections"/>
<value value="23234352356"/>
</identifier>
<!-- status is really about the specimen availability and includes the concepts available - The physical specimen is present and in good condition entered-in-error - The specimen was entered in error and therefore nullified. unavailable - There is no physical specimen because it is either lost, destroyed or consumed. unsatisfactory - The specimen cannot be used because of either a quality issue such as a broken container, contamination, or too old. -->
<status value="available"/>
<!--
Type is a loosely defined field because there is such a lot of variation in how it is used.
The principal variation is how much information that could be represented elsewhere is also
represented here. For instance, here's some possible types:
lithium heparin plasma (+ .container.additive) (e.g. SNOMED CT 446272009)
transfusion bag of blood (+ container.type)
Peritoneal lavage (+ collection.bodySite)
If the type includes other fields, it would be normal not to populate the other fields
Note that this practice is so widespread that it's pointless to try and stop it -->
<type>
<coding>
<system value="http://snomed.info/sct"/>
<code value="122555007"/>
<display value="Venous blood specimen"/>
</coding>
</type>
<subject>
<reference value="Patient/example"/>
<display value="Peter Patient"/>
</subject>
<!-- accession identifier - e.g. assigned by the labaratory when it is received.
This is common, unlike specimen identifier -->
<accessionIdentifier>
<system value="http://lab.acme.org/specimens/2011"/>
<value value="X352356"/>
</accessionIdentifier>
<receivedTime value="2011-03-04T07:03:00Z"/>
<collection>
<collector>
<!-- in practice, collecter is almost always recorded -->
<reference value="Practitioner/example"/>
</collector>
<comment value="Specimen is grossly lipemic"/>
<!-- the time of collection is usually required. Usually a point in time, but can be a period
(collectedPeriod) if it's a timed collection (e.g. a 24 hour urine) -->
<collectedDateTime value="2011-05-30T06:15:00Z"/>
<quantity>
<value value="6"/>
<unit value="mL"/>
<!-- e.g. full -->
</quantity>
<!-- method is usually implied by type -->
<method>
<coding>
<system value="http://hl7.org/fhir/v2/0488"/>
<code value="LNV"/>
</coding>
</method>
</collection>
<container>
<!--
the container identifier is not the same as the specimen identifier
usually, it is pre-printed/implanted etc.on the container prior to
use. It might a RFID in the container, or it might be a UDI
(http://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/UniqueDeviceIdentification/)
-->
<identifier>
<!-- this is a serial number off the tube - there's no context such as a system -->
<value value="48736-15394-75465"/>
</identifier>
<description value="Green Gel tube"/>
<type>
<!-- again, this might easily be used to cover additives and capacity as well -->
<text value="Vacutainer"/>
</type>
<capacity>
<value value="10"/>
<unit value="mL"/>
</capacity>
<!-- if there's only one container, then this value is the same
as .collection.quantity (usually). This is for when there is more
than one container -->
<specimenQuantity>
<value value="6"/>
<unit value="mL"/>
</specimenQuantity>
<additiveReference>
<reference value="#hep"/>
</additiveReference>
</container>
</Specimen>

View File

@ -59,6 +59,7 @@ import org.hl7.fhir.instance.model.api.IBaseXhtml;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.util.CoverageIgnore;
@DatatypeDef(name="xhtml")
public class XhtmlNode implements IBaseXhtml {
@ -370,4 +371,33 @@ public class XhtmlNode implements IBaseXhtml {
setValueAsString(theValue);
return this;
}
/**
* Returns false
*/
@Override
@CoverageIgnore
public boolean hasFormatComment() {
return false;
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPre() {
throw new UnsupportedOperationException();
}
/**
* NOT SUPPORTED - Throws {@link UnsupportedOperationException}
*/
@Override
@CoverageIgnore
public List<String> getFormatCommentsPost() {
throw new UnsupportedOperationException();
}
}

View File

@ -1,5 +1,4 @@
<Patient xmlns="http://hl7.org/fhir">
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://hl7.org/fhir ./fhir-single.xsd"> -->
<extension url="urn:patientext:att">
<valueAttachment>
<contentType value="aaaa"/>
@ -46,7 +45,6 @@
</div>
</text>
<!-- MRN assigned by ACME healthcare on 6-May 2001 -->
<identifier>
<use value="usual"/>
<system value="urn:oid:1.2.36.146.595.217.0.1"/>
@ -61,7 +59,6 @@
<active value="true"/>
<!-- Peter James Chalmers, but called &quot;Jim&quot; -->
<name>
<use value="official"/>
<family value="Chalmers"/>
@ -75,7 +72,6 @@
<telecom>
<use value="home"/>
<!-- home communication details aren't known -->
</telecom>
<telecom>
<system value="phone"/>
@ -83,7 +79,6 @@
<use value="work"/>
</telecom>
<!-- use FHIR code system for male / female -->
<gender value="male"/>
<birthDate value="1974-12-25"/>
<deceasedBoolean value="false"/>
@ -111,7 +106,6 @@
<name>
<family value="du">
<!-- the &quot;du&quot; part is a family name prefix (VV in iso 21090) -->
<extension url="http://hl7.org/fhir/Profile/iso-21090#qualifier">
<valueCode value="VV"/>
</extension>

View File

@ -22,7 +22,7 @@ package org.hl7.fhir.instance.model;
*/
public interface IIdType {
public interface IIdType extends IBase {
boolean isEmpty();