Fix #335 (also fixes #336) - Correctly parse and serialize IDs on elements within a resource

This commit is contained in:
jamesagnew 2016-04-17 10:12:34 -04:00
parent 3f2b5fdeb7
commit 1af65ff5a8
13 changed files with 669 additions and 102 deletions

View File

@ -97,7 +97,7 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
}
@Override
public IPrimitiveType<T> setValue(T theValue) throws DataFormatException {
public BasePrimitive<T> setValue(T theValue) throws DataFormatException {
myCoercedValue = theValue;
updateStringValue();
return this;

View File

@ -42,6 +42,7 @@ import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseElement;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
@ -65,6 +66,7 @@ import ca.uhn.fhir.context.RuntimeChildNarrativeDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IIdentifiableElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
@ -105,10 +107,10 @@ public abstract class BaseParser implements IParser {
}
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final CompositeChildElement theParent) {
BaseRuntimeElementCompositeDefinition<?> elementDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(theCompositeElement.getClass());
final List<BaseRuntimeChildDefinition> children = elementDef.getChildrenAndExtension();
return new Iterable<BaseParser.CompositeChildElement>() {
@Override
public Iterator<CompositeChildElement> iterator() {
@ -143,9 +145,9 @@ public abstract class BaseParser implements IParser {
/*
* There are lots of reasons we might skip encoding a particular child
*/
// if (myNext.getDef().getElementName().equals("extension") || myNext.getDef().getElementName().equals("modifierExtension")) {
// myNext = null;
// } else
// if (myNext.getDef().getElementName().equals("extension") || myNext.getDef().getElementName().equals("modifierExtension")) {
// myNext = null;
// } else
if (myNext.getDef().getElementName().equals("id")) {
myNext = null;
} else if (!myNext.shouldBeEncoded()) {
@ -377,7 +379,7 @@ public abstract class BaseParser implements IParser {
if (theResource.getStructureFhirVersionEnum() != myContext.getVersion().getVersion()) {
throw new IllegalArgumentException("This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
}
doEncodeResourceToWriter(theResource, theWriter);
}
@ -411,6 +413,18 @@ public abstract class BaseParser implements IParser {
return retVal;
}
protected String getCompositeElementId(IBase theElement) {
String elementId = null;
if (!(theElement instanceof IBaseResource)) {
if (theElement instanceof IBaseElement) {
elementId = ((IBaseElement) theElement).getId();
} else if (theElement instanceof IIdentifiableElement) {
elementId = ((IIdentifiableElement) theElement).getElementSpecificId();
}
}
return elementId;
}
ContainedResources getContainedResources() {
return myContainedResources;
}
@ -552,14 +566,14 @@ public abstract class BaseParser implements IParser {
@Override
public <T extends IBaseResource> T parseResource(Class<T> theResourceType, Reader theReader) throws DataFormatException {
if (theResourceType != null) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
if (def.getStructureVersion() != myContext.getVersion().getVersion()) {
throw new IllegalArgumentException("This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not parse a structure for version " + def.getStructureVersion());
}
}
T retVal = doParseResource(theResourceType, theReader);
RuntimeResourceDefinition def = myContext.getResourceDefinition(retVal);
@ -684,20 +698,20 @@ public abstract class BaseParser implements IParser {
@SuppressWarnings("unchecked")
List<IBase> retVal = (List<IBase>) theValues;
for (int i = 0; i < retVal.size(); i++) {
IBase next = retVal.get(i);
/*
* If we have automatically contained any resources via
* their references, this ensures that we output the new
* local reference
*/
if (next instanceof IBaseReference) {
IBaseReference nextRef = (IBaseReference)next;
IBaseReference nextRef = (IBaseReference) next;
String refText = determineReferenceText(nextRef);
if (!StringUtils.equals(refText, nextRef.getReferenceElement().getValue())) {
if (retVal == theValues) {
retVal = new ArrayList<IBase>(theValues);
}
@ -705,11 +719,11 @@ public abstract class BaseParser implements IParser {
myContext.newTerser().cloneInto(nextRef, newRef, true);
newRef.setReference(refText);
retVal.set(i, newRef);
}
}
}
return retVal;
}

View File

@ -56,6 +56,7 @@ import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype;
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
import org.hl7.fhir.instance.model.api.IBaseElement;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
@ -140,7 +141,7 @@ public class JsonParser extends BaseParser implements IParser {
myContext = theContext;
}
private void addToHeldComments(int valueIdx, List<String> theCommentsToAdd, ArrayList<ArrayList<String>> theListToAddTo) {
private boolean addToHeldComments(int valueIdx, List<String> theCommentsToAdd, ArrayList<ArrayList<String>> theListToAddTo) {
if (theCommentsToAdd.size() > 0) {
theListToAddTo.ensureCapacity(valueIdx);
while (theListToAddTo.size() <= valueIdx) {
@ -150,10 +151,13 @@ public class JsonParser extends BaseParser implements IParser {
theListToAddTo.set(valueIdx, new ArrayList<String>());
}
theListToAddTo.get(valueIdx).addAll(theCommentsToAdd);
return true;
} else {
return false;
}
}
private void addToHeldExtensions(int valueIdx, List<? extends IBaseExtension<?, ?>> ext, ArrayList<ArrayList<HeldExtension>> list, boolean theIsModifier) {
private boolean addToHeldExtensions(int valueIdx, List<? extends IBaseExtension<?, ?>> ext, ArrayList<ArrayList<HeldExtension>> list, boolean theIsModifier) {
if (ext.size() > 0) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
@ -165,6 +169,9 @@ public class JsonParser extends BaseParser implements IParser {
for (IBaseExtension<?, ?> next : ext) {
list.get(valueIdx).add(new HeldExtension(next, theIsModifier));
}
return true;
} else {
return false;
}
}
@ -400,8 +407,8 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd();
}
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theContainedResource, CompositeChildElement theChildElem)
throws IOException {
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theContainedResource, CompositeChildElement theChildElem,
boolean theForceEmpty) throws IOException {
switch (theChildDef.getChildType()) {
case ID_DATATYPE: {
@ -420,6 +427,9 @@ public class JsonParser extends BaseParser implements IParser {
case PRIMITIVE_DATATYPE: {
final IPrimitiveType<?> value = (IPrimitiveType<?>) theNextValue;
if (isBlank(value.getValueAsString())) {
if (theForceEmpty) {
theWriter.writeNull();
}
break;
}
@ -460,7 +470,7 @@ public class JsonParser extends BaseParser implements IParser {
}
break;
}
case RESOURCE_REF:
case RESOURCE_REF:
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
if (theChildName != null) {
@ -523,14 +533,20 @@ public class JsonParser extends BaseParser implements IParser {
}
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, JsonGenerator theEventWriter, boolean theContainedResource, CompositeChildElement theParent)
throws IOException {
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, JsonGenerator theEventWriter, boolean theContainedResource, CompositeChildElement theParent) throws IOException {
{
String elementId = getCompositeElementId(theElement);
if (isNotBlank(elementId)) {
theEventWriter.write("id", elementId);
}
}
boolean haveWrittenExtensions = false;
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent)) {
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
if (nextChildElem.getDef().getElementName().equals("extension") || nextChildElem.getDef().getElementName().equals("modifierExtension") || nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
if (!haveWrittenExtensions) {
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource);
@ -538,7 +554,7 @@ public class JsonParser extends BaseParser implements IParser {
}
continue;
}
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
INarrativeGenerator gen = myContext.getNarrativeGenerator();
if (gen != null) {
@ -556,7 +572,7 @@ public class JsonParser extends BaseParser implements IParser {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource, nextChildElem);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource, nextChildElem, false);
continue;
}
}
@ -564,7 +580,7 @@ public class JsonParser extends BaseParser implements IParser {
} else if (nextChild instanceof RuntimeChildContainedResources) {
String childName = nextChild.getValidChildNames().iterator().next();
BaseRuntimeElementDefinition<?> child = nextChild.getChildByName(childName);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource, nextChildElem);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource, nextChildElem, false);
continue;
}
@ -581,6 +597,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);
ArrayList<String> ids = new ArrayList<String>(0);
int valueIdx = 0;
for (IBase nextValue : values) {
@ -596,13 +613,10 @@ public class JsonParser extends BaseParser implements IParser {
}
Class<? extends IBase> type = nextValue.getClass();
String childName = nextChild.getChildNameByDatatype(type);
BaseRuntimeElementDefinition<?> childDef = nextChild.getChildElementDefinitionByDatatype(type);
if (childDef == null) {
// if (IBaseExtension.class.isAssignableFrom(type)) {
// continue;
// }
super.throwExceptionForUnknownChildType(nextChild, type);
}
boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE;
@ -611,55 +625,54 @@ public class JsonParser extends BaseParser implements IParser {
continue;
}
// if (nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
// RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild;
// new HeldExtension(extDef, nextValue).write(theResDef, theResource, theEventWriter);
// } else {
boolean force = false;
if (primitive) {
if (nextValue instanceof ISupportsUndeclaredExtensions) {
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
force |= addToHeldExtensions(valueIdx, ext, extensions, false);
if (currentChildName == null || !currentChildName.equals(childName)) {
if (inArray) {
theEventWriter.writeEnd();
}
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
theEventWriter.writeStartArray(childName);
inArray = true;
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem);
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
// suppress narratives from contained resources
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, nextChildElem);
}
currentChildName = childName;
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true);
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem);
}
if (primitive) {
if (nextValue instanceof ISupportsUndeclaredExtensions) {
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
addToHeldExtensions(valueIdx, ext, extensions, false);
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
addToHeldExtensions(valueIdx, ext, modifierExtensions, true);
} else {
if (nextValue instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) nextValue;
List<? extends IBaseExtension<?, ?>> ext = element.getExtension();
addToHeldExtensions(valueIdx, ext, extensions, false);
}
if (nextValue instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
List<? extends IBaseExtension<?, ?>> ext = element.getModifierExtension();
addToHeldExtensions(valueIdx, ext, extensions, true);
}
if (nextValue instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) nextValue;
List<? extends IBaseExtension<?, ?>> ext = element.getExtension();
force |= addToHeldExtensions(valueIdx, ext, extensions, false);
}
if (nextValue.hasFormatComment()) {
addToHeldComments(valueIdx, nextValue.getFormatCommentsPre(), comments);
addToHeldComments(valueIdx, nextValue.getFormatCommentsPost(), comments);
if (nextValue instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
List<? extends IBaseExtension<?, ?>> ext = element.getModifierExtension();
force |= addToHeldExtensions(valueIdx, ext, extensions, true);
}
}
if (nextValue.hasFormatComment()) {
force |= addToHeldComments(valueIdx, nextValue.getFormatCommentsPre(), comments);
force |= addToHeldComments(valueIdx, nextValue.getFormatCommentsPost(), comments);
}
String elementId = getCompositeElementId(nextValue);
if (isNotBlank(elementId)) {
force = true;
addToHeldIds(valueIdx, ids, elementId);
}
}
// }
if (currentChildName == null || !currentChildName.equals(childName)) {
if (inArray) {
theEventWriter.writeEnd();
}
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
theEventWriter.writeStartArray(childName);
inArray = true;
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force);
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
// suppress narratives from contained resources
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, nextChildElem, force);
}
currentChildName = childName;
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force);
}
valueIdx++;
}
@ -701,12 +714,21 @@ public class JsonParser extends BaseParser implements IParser {
haveContent = true;
}
String elementId = null;
if (ids.size() > i) {
elementId = ids.get(i);
haveContent |= isNotBlank(elementId);
}
if (!haveContent) {
theEventWriter.writeNull();
} else {
if (inArray) {
theEventWriter.writeStartObject();
}
if (isNotBlank(elementId)) {
theEventWriter.write("id", elementId);
}
if (nextComments != null && !nextComments.isEmpty()) {
theEventWriter.writeStartArray("fhir_comments");
for (String next : nextComments) {
@ -726,8 +748,17 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, boolean theContainedResource, CompositeChildElement theParent)
throws IOException, DataFormatException {
private void addToHeldIds(int theValueIdx, ArrayList<String> theListToAddTo, String theId) {
theListToAddTo.ensureCapacity(theValueIdx);
while (theListToAddTo.size() <= theValueIdx) {
theListToAddTo.add(null);
}
if (theListToAddTo.get(theValueIdx) == null) {
theListToAddTo.set(theValueIdx, theId);
}
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, boolean theContainedResource, CompositeChildElement theParent) throws IOException, DataFormatException {
writeCommentsPreAndPost(theNextValue, theEventWriter);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theParent);
@ -802,7 +833,7 @@ public class JsonParser extends BaseParser implements IParser {
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
profiles = super.getProfileTagsForEncoding(resource, profiles);
TagList tags = getMetaTagsForEncoding(resource);
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
@ -1305,6 +1336,9 @@ public class JsonParser extends BaseParser implements IParser {
theState.endingElement();
break;
case NULL:
theState.enteringNewElement(null, theName);
parseAlternates(theAlternateVal, theState, theAlternateName);
theState.endingElement();
break;
}
}
@ -1564,7 +1598,7 @@ public class JsonParser extends BaseParser implements IParser {
public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter) throws IOException {
if (myUndeclaredExtension != null) {
writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, myUndeclaredExtension);
writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension);
} else {
theEventWriter.writeStartObject();
@ -1577,14 +1611,14 @@ public class JsonParser extends BaseParser implements IParser {
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource);
} else {
String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, null);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, null, false);
}
theEventWriter.writeEnd();
}
}
private void writeUndeclaredExtInDstu1Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, IBaseExtension<?, ?> ext) throws IOException {
private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, IBaseExtension<?, ?> ext) throws IOException {
IBase value = ext.getValue();
String extensionUrl = ext.getUrl();
@ -1592,6 +1626,11 @@ public class JsonParser extends BaseParser implements IParser {
writeCommentsPreAndPost(myUndeclaredExtension, theEventWriter);
String elementId = getCompositeElementId(ext);
if (isNotBlank(elementId)) {
theEventWriter.write("id", getCompositeElementId(ext));
}
theEventWriter.write("url", extensionUrl);
boolean noValue = value == null || value.isEmpty();
@ -1606,17 +1645,17 @@ public class JsonParser extends BaseParser implements IParser {
}
for (Object next : ext.getExtension()) {
writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, (IBaseExtension<?, ?>) next);
writeUndeclaredExtension(theResDef, theResource, theEventWriter, (IBaseExtension<?, ?>) next);
}
theEventWriter.writeEnd();
} else {
/*
/*
* Pre-process value - This is called in case the value is a reference
* since we might modify the text
* since we might modify the text
*/
value = JsonParser.super.preProcessValues(myDef, theResource, Collections.singletonList(value)).get(0);
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
if (childName == null) {
@ -1626,7 +1665,7 @@ public class JsonParser extends BaseParser implements IParser {
if (childDef == null) {
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
}
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, null);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, null, false);
}
// theEventWriter.name(myUndeclaredExtension.get);

View File

@ -94,15 +94,15 @@ 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 final FhirContext myContext;
private final IParserErrorHandler myErrorHandler;
private final boolean myJsonMode;
private T myObject;
private BaseState myState;
private IBase myPreviousElement;
private final IParser myParser;
private IBase myPreviousElement;
private BaseState myState;
private ParserState(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
myParser = theParser;
myContext = theContext;
@ -1121,10 +1121,6 @@ class ParserState<T> {
}
}
protected BundleEntry getEntry() {
return myEntry;
}
@SuppressWarnings("deprecation")
private void populateResourceMetadata() {
if (myEntry.getResource() == null) {
@ -1624,6 +1620,13 @@ class ParserState<T> {
try {
child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName);
} catch (DataFormatException e) {
if (theChildName.equals("id")) {
if (getCurrentElement() instanceof IIdentifiableElement) {
push(new IdentifiableElementIdState(getPreResourceState(), (IIdentifiableElement) getCurrentElement()));
return;
}
}
/*
* 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
@ -1751,6 +1754,27 @@ class ParserState<T> {
}
public class ElementIdState extends BaseState {
private IBaseElement myElement;
public ElementIdState(ParserState<T>.PreResourceState thePreResourceState, IBaseElement theElement) {
super(thePreResourceState);
myElement = theElement;
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
myElement.setId(theValue);
}
@Override
public void endingElement() {
pop();
}
}
private class ExtensionState extends BaseState {
private IBaseExtension<?, ?> myExtension;
@ -1767,6 +1791,15 @@ class ParserState<T> {
// of "value" like every single other place
return;
}
if ("id".equals(theName)) {
if (getCurrentElement() instanceof IBaseElement) {
((IBaseElement)getCurrentElement()).setId(theValue);
return;
} else if (getCurrentElement() instanceof IIdentifiableElement) {
((IIdentifiableElement)getCurrentElement()).setElementSpecificId(theValue);
return;
}
}
super.attributeValue(theName, theValue);
}
@ -1780,6 +1813,16 @@ class ParserState<T> {
@Override
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
if (theLocalPart.equals("id")) {
if (getCurrentElement() instanceof IBaseElement) {
push(new ElementIdState(getPreResourceState(), (IBaseElement)getCurrentElement()));
return;
} else if (getCurrentElement() instanceof IIdentifiableElement) {
push(new IdentifiableElementIdState(getPreResourceState(), (IIdentifiableElement)getCurrentElement()));
return;
}
}
BaseRuntimeElementDefinition<?> target = myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(theLocalPart);
if (target == null) {
myErrorHandler.unknownElement(null, theLocalPart);
@ -1836,6 +1879,27 @@ class ParserState<T> {
}
public class IdentifiableElementIdState extends BaseState {
private IIdentifiableElement myElement;
public IdentifiableElementIdState(ParserState<T>.PreResourceState thePreResourceState, IIdentifiableElement theElement) {
super(thePreResourceState);
myElement = theElement;
}
@Override
public void attributeValue(String theName, String theValue) throws DataFormatException {
myElement.setElementSpecificId(theValue);
}
@Override
public void endingElement() {
pop();
}
}
private class MetaElementState extends BaseState {
private ResourceMetadataMap myMap;

View File

@ -518,6 +518,10 @@ public class XmlParser extends BaseParser implements IParser {
String value = pd.getValueAsString();
if (value != null || super.hasExtensions(pd)) {
theEventWriter.writeStartElement(childName);
String elementId = getCompositeElementId(theElement);
if (isNotBlank(elementId)) {
theEventWriter.writeAttribute("id", elementId);
}
if (value != null) {
theEventWriter.writeAttribute("value", value);
}
@ -530,10 +534,13 @@ public class XmlParser extends BaseParser implements IParser {
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
theEventWriter.writeStartElement(childName);
String elementId = getCompositeElementId(theElement);
if (isNotBlank(elementId)) {
theEventWriter.writeAttribute("id", elementId);
}
if (isNotBlank(theExtensionUrl)) {
theEventWriter.writeAttribute("url", theExtensionUrl);
}
BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef;
encodeCompositeElementToStreamWriter(theResource, theElement, theEventWriter, theIncludedResource, theParent);
theEventWriter.writeEndElement();
break;
@ -592,6 +599,7 @@ public class XmlParser extends BaseParser implements IParser {
@SuppressWarnings("rawtypes")
private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent)
throws XMLStreamException, DataFormatException {
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent)) {
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
@ -701,6 +709,11 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.writeStartElement("extension");
}
String elementId = getCompositeElementId(nextValue);
if (isNotBlank(elementId)) {
theEventWriter.writeAttribute("id", elementId);
}
theEventWriter.writeAttribute("url", extensionUrl);
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theContainedResource, nextChildElem);
theEventWriter.writeEndElement();
@ -892,18 +905,23 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theEventWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
for (IBaseExtension<?, ?> next : theExtensions) {
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
continue;
}
writeCommentsPre(theWriter, next);
writeCommentsPre(theEventWriter, next);
theWriter.writeStartElement(tagName);
theEventWriter.writeStartElement(tagName);
String elementId = getCompositeElementId(next);
if (isNotBlank(elementId)) {
theEventWriter.writeAttribute("id", elementId);
}
String url = next.getUrl();
theWriter.writeAttribute("url", url);
theEventWriter.writeAttribute("url", url);
if (next.getValue() != null) {
IBaseDatatype value = next.getValue();
@ -923,15 +941,15 @@ public class XmlParser extends BaseParser implements IParser {
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
}
}
encodeChildElementToStreamWriter(theResource, theWriter, value, childName, childDef, null, theIncludedResource, null);
encodeChildElementToStreamWriter(theResource, theEventWriter, value, childName, childDef, null, theIncludedResource, null);
}
// child extensions
encodeExtensionsIfPresent(theResource, theWriter, next, theIncludedResource);
encodeExtensionsIfPresent(theResource, theEventWriter, next, theIncludedResource);
theWriter.writeEndElement();
theEventWriter.writeEndElement();
writeCommentsPost(theWriter, next);
writeCommentsPost(theEventWriter, next);
}
}

View File

@ -24,4 +24,6 @@ public interface IBaseElement {
IBaseElement setId(String theValue);
String getId();
}

View File

@ -83,6 +83,63 @@ public class JsonParserDstu2Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
/**
* See #336
*/
@Test
public void testEncodeAndParseNullPrimitiveWithExtensions() {
Patient p = new Patient();
p.setId("patid");
HumanNameDt name = p.addName();
name.addFamily().setValue(null).addUndeclaredExtension(new ExtensionDt(false, "http://foo", new StringDt("FOOEXT0")));
name.getFamily().get(0).setElementSpecificId("f0");
name.addFamily().setValue("V1").addUndeclaredExtension((ExtensionDt) new ExtensionDt(false, "http://foo", new StringDt("FOOEXT1")));
name.getFamily().get(1).setElementSpecificId("f1");
name.getFamily().get(1).getUndeclaredExtensions().get(0).setElementSpecificId("ext1id");
name.addFamily(); // this one shouldn't get encoded
name.addFamily().setValue(null).addUndeclaredExtension(new ExtensionDt(false, "http://foo", new StringDt("FOOEXT3")));
name.setElementSpecificId("nameid");
String output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
output = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(p);
String expected = "{\"resourceType\":\"Patient\",\"id\":\"patid\",\"name\":[{\"id\":\"nameid\",\"family\":[null,\"V1\",null],\"_family\":[{\"id\":\"f0\",\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"FOOEXT0\"}]},{\"id\":\"f1\",\"extension\":[{\"id\":\"ext1id\",\"url\":\"http://foo\",\"valueString\":\"FOOEXT1\"}]},{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"FOOEXT3\"}]}]}]}";
assertEquals(expected, output);
p = ourCtx.newJsonParser().parseResource(Patient.class, output);
assertEquals("patid", p.getIdElement().getIdPart());
name = p.getName().get(0);
assertEquals("nameid", name.getElementSpecificId());
assertEquals(3, name.getFamily().size());
assertEquals(null, name.getFamily().get(0).getValue());
assertEquals("V1", name.getFamily().get(1).getValue());
assertEquals(null, name.getFamily().get(2).getValue());
assertEquals("f0", name.getFamily().get(0).getElementSpecificId());
assertEquals("f1", name.getFamily().get(1).getElementSpecificId());
assertEquals(null, name.getFamily().get(2).getElementSpecificId());
assertEquals(1, name.getFamily().get(0).getAllUndeclaredExtensions().size());
assertEquals("http://foo", name.getFamily().get(0).getAllUndeclaredExtensions().get(0).getUrl());
assertEquals("FOOEXT0", ((StringDt)name.getFamily().get(0).getAllUndeclaredExtensions().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(0).getAllUndeclaredExtensions().get(0).getElementSpecificId());
assertEquals(1, name.getFamily().get(1).getAllUndeclaredExtensions().size());
assertEquals("http://foo", name.getFamily().get(1).getAllUndeclaredExtensions().get(0).getUrl());
assertEquals("FOOEXT1", ((StringDt)name.getFamily().get(1).getAllUndeclaredExtensions().get(0).getValue()).getValue());
assertEquals("ext1id", name.getFamily().get(1).getAllUndeclaredExtensions().get(0).getElementSpecificId());
assertEquals(1, name.getFamily().get(2).getAllUndeclaredExtensions().size());
assertEquals("http://foo", name.getFamily().get(2).getAllUndeclaredExtensions().get(0).getUrl());
assertEquals("FOOEXT3", ((StringDt)name.getFamily().get(2).getAllUndeclaredExtensions().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(2).getAllUndeclaredExtensions().get(0).getElementSpecificId());
}
@Test
public void testContainedResourceInExtensionUndeclared() {

View File

@ -112,6 +112,62 @@ public class XmlParserDstu2Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
/**
* See #336
*/
@Test
public void testEncodeAndParseNullPrimitiveWithExtensions() {
Patient p = new Patient();
p.setId("patid");
HumanNameDt name = p.addName();
name.addFamily().setValue(null).addUndeclaredExtension(new ExtensionDt(false, "http://foo", new StringDt("FOOEXT0")));
name.getFamily().get(0).setElementSpecificId("f0");
name.addFamily().setValue("V1").addUndeclaredExtension((ExtensionDt) new ExtensionDt(false, "http://foo", new StringDt("FOOEXT1")));
name.getFamily().get(1).setElementSpecificId("f1");
name.getFamily().get(1).getUndeclaredExtensions().get(0).setElementSpecificId("ext1id");
name.addFamily(); // this one shouldn't get encoded
name.addFamily().setValue(null).addUndeclaredExtension(new ExtensionDt(false, "http://foo", new StringDt("FOOEXT3")));
name.setElementSpecificId("nameid");
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
output = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(p);
String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><id value=\"patid\"/><name id=\"nameid\"><family id=\"f0\"><extension url=\"http://foo\"><valueString value=\"FOOEXT0\"/></extension></family><family id=\"f1\" value=\"V1\"><extension id=\"ext1id\" url=\"http://foo\"><valueString value=\"FOOEXT1\"/></extension></family><family><extension url=\"http://foo\"><valueString value=\"FOOEXT3\"/></extension></family></name></Patient>";
assertEquals(expected, output);
p = ourCtx.newXmlParser().parseResource(Patient.class, output);
assertEquals("patid", p.getIdElement().getIdPart());
name = p.getName().get(0);
assertEquals("nameid", name.getElementSpecificId());
assertEquals(3, name.getFamily().size());
assertEquals(null, name.getFamily().get(0).getValue());
assertEquals("V1", name.getFamily().get(1).getValue());
assertEquals(null, name.getFamily().get(2).getValue());
assertEquals("f0", name.getFamily().get(0).getElementSpecificId());
assertEquals("f1", name.getFamily().get(1).getElementSpecificId());
assertEquals(null, name.getFamily().get(2).getElementSpecificId());
assertEquals(1, name.getFamily().get(0).getAllUndeclaredExtensions().size());
assertEquals("http://foo", name.getFamily().get(0).getAllUndeclaredExtensions().get(0).getUrl());
assertEquals("FOOEXT0", ((StringDt)name.getFamily().get(0).getAllUndeclaredExtensions().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(0).getAllUndeclaredExtensions().get(0).getElementSpecificId());
assertEquals(1, name.getFamily().get(1).getAllUndeclaredExtensions().size());
assertEquals("http://foo", name.getFamily().get(1).getAllUndeclaredExtensions().get(0).getUrl());
assertEquals("FOOEXT1", ((StringDt)name.getFamily().get(1).getAllUndeclaredExtensions().get(0).getValue()).getValue());
assertEquals("ext1id", name.getFamily().get(1).getAllUndeclaredExtensions().get(0).getElementSpecificId());
assertEquals(1, name.getFamily().get(2).getAllUndeclaredExtensions().size());
assertEquals("http://foo", name.getFamily().get(2).getAllUndeclaredExtensions().get(0).getUrl());
assertEquals("FOOEXT3", ((StringDt)name.getFamily().get(2).getAllUndeclaredExtensions().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(2).getAllUndeclaredExtensions().get(0).getElementSpecificId());
}
@ResourceDef(name="Patient")
public static class TestPatientFor327 extends Patient

View File

@ -43,7 +43,7 @@ import org.hl7.fhir.dstu3.exceptions.FHIRException;
/**
* Base definition for all elements in a resource.
*/
public abstract class Element extends Base implements IBaseHasExtensions {
public abstract class Element extends Base implements IBaseHasExtensions, IBaseElement {
/**
* unique id for the element within a resource (for internal references).

View File

@ -82,12 +82,79 @@ public class JsonParserDstu3Test {
ourCtx.setNarrativeGenerator(null);
}
/**
* See #336
*/
@Test
public void testEncodeAndParseNullPrimitiveWithExtensions() {
Patient p = new Patient();
p.setId("patid");
HumanName name = p.addName();
name.addFamilyElement().setValue(null).setId("f0").addExtension(new Extension("http://foo", new StringType("FOOEXT0")));
name.addFamilyElement().setValue("V1").setId("f1").addExtension((Extension) new Extension("http://foo", new StringType("FOOEXT1")).setId("ext1id"));
name.addFamilyElement(); // this one shouldn't get encoded
name.addFamilyElement().setValue(null).addExtension(new Extension("http://foo", new StringType("FOOEXT3")));
name.setId("nameid");
String output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
output = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(p);
String expected = "{\"resourceType\":\"Patient\",\"id\":\"patid\",\"name\":[{\"id\":\"nameid\",\"family\":[null,\"V1\",null],\"_family\":[{\"id\":\"f0\",\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"FOOEXT0\"}]},{\"id\":\"f1\",\"extension\":[{\"id\":\"ext1id\",\"url\":\"http://foo\",\"valueString\":\"FOOEXT1\"}]},{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"FOOEXT3\"}]}]}]}";
assertEquals(expected, output);
p = ourCtx.newJsonParser().parseResource(Patient.class, output);
assertEquals("patid", p.getIdElement().getIdPart());
name = p.getName().get(0);
assertEquals("nameid", name.getId());
assertEquals(3, name.getFamily().size());
assertEquals(null, name.getFamily().get(0).getValue());
assertEquals("V1", name.getFamily().get(1).getValue());
assertEquals(null, name.getFamily().get(2).getValue());
assertEquals("f0", name.getFamily().get(0).getId());
assertEquals("f1", name.getFamily().get(1).getId());
assertEquals(null, name.getFamily().get(2).getId());
assertEquals(1, name.getFamily().get(0).getExtension().size());
assertEquals("http://foo", name.getFamily().get(0).getExtension().get(0).getUrl());
assertEquals("FOOEXT0", ((StringType)name.getFamily().get(0).getExtension().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(0).getExtension().get(0).getId());
assertEquals(1, name.getFamily().get(1).getExtension().size());
assertEquals("http://foo", name.getFamily().get(1).getExtension().get(0).getUrl());
assertEquals("FOOEXT1", ((StringType)name.getFamily().get(1).getExtension().get(0).getValue()).getValue());
assertEquals("ext1id", name.getFamily().get(1).getExtension().get(0).getId());
assertEquals(1, name.getFamily().get(2).getExtension().size());
assertEquals("http://foo", name.getFamily().get(2).getExtension().get(0).getUrl());
assertEquals("FOOEXT3", ((StringType)name.getFamily().get(2).getExtension().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(2).getExtension().get(0).getId());
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
/**
* See #335
*/
@Test
public void testParseExtensionWithId() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/json-edge-case-modified-335.json"));
Patient p = ourCtx.newJsonParser().parseResource(Patient.class, input);
StringType family1 = p.getContact().get(0).getName().getFamily().get(1);
assertEquals("du", family1.getValue());
assertEquals("a2", family1.getId());
}
@Test
public void testEncodeAndParseExtensions() throws Exception {

View File

@ -562,6 +562,60 @@ public class XmlParserDstu3Test {
assertEquals("label2", tagList.get(1).getDisplay());
}
/**
* See #336
*/
@Test
public void testEncodeAndParseNullPrimitiveWithExtensions() {
Patient p = new Patient();
p.setId("patid");
HumanName name = p.addName();
name.addFamilyElement().setValue(null).setId("f0").addExtension(new Extension("http://foo", new StringType("FOOEXT0")));
name.addFamilyElement().setValue("V1").setId("f1").addExtension((Extension) new Extension("http://foo", new StringType("FOOEXT1")).setId("ext1id"));
name.addFamilyElement(); // this one shouldn't get encoded
name.addFamilyElement().setValue(null).addExtension(new Extension("http://foo", new StringType("FOOEXT3")));
name.setId("nameid");
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
output = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(p);
String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><id value=\"patid\"/><name id=\"nameid\"><family id=\"f0\"><extension url=\"http://foo\"><valueString value=\"FOOEXT0\"/></extension></family><family id=\"f1\" value=\"V1\"><extension id=\"ext1id\" url=\"http://foo\"><valueString value=\"FOOEXT1\"/></extension></family><family><extension url=\"http://foo\"><valueString value=\"FOOEXT3\"/></extension></family></name></Patient>";
assertEquals(expected, output);
p = ourCtx.newXmlParser().parseResource(Patient.class, output);
assertEquals("patid", p.getIdElement().getIdPart());
name = p.getName().get(0);
assertEquals("nameid", name.getId());
assertEquals(3, name.getFamily().size());
assertEquals(null, name.getFamily().get(0).getValue());
assertEquals("V1", name.getFamily().get(1).getValue());
assertEquals(null, name.getFamily().get(2).getValue());
assertEquals("f0", name.getFamily().get(0).getId());
assertEquals("f1", name.getFamily().get(1).getId());
assertEquals(null, name.getFamily().get(2).getId());
assertEquals(1, name.getFamily().get(0).getExtension().size());
assertEquals("http://foo", name.getFamily().get(0).getExtension().get(0).getUrl());
assertEquals("FOOEXT0", ((StringType)name.getFamily().get(0).getExtension().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(0).getExtension().get(0).getId());
assertEquals(1, name.getFamily().get(1).getExtension().size());
assertEquals("http://foo", name.getFamily().get(1).getExtension().get(0).getUrl());
assertEquals("FOOEXT1", ((StringType)name.getFamily().get(1).getExtension().get(0).getValue()).getValue());
assertEquals("ext1id", name.getFamily().get(1).getExtension().get(0).getId());
assertEquals(1, name.getFamily().get(2).getExtension().size());
assertEquals("http://foo", name.getFamily().get(2).getExtension().get(0).getUrl());
assertEquals("FOOEXT3", ((StringType)name.getFamily().get(2).getExtension().get(0).getValue()).getValue());
assertEquals(null, name.getFamily().get(2).getExtension().get(0).getId());
}
/**
* Test for #233
*/

View File

@ -0,0 +1,190 @@
{
"resourceType": "Patient",
"identifier": [{
"period": {"start": "2001-05-06"},
"assigner": {"display": "Acme\u202fHealthcare"},
"use": "usual",
"system": "urn:oid:1.2.36.146.595.217.0.1",
"value": "12345"
}],
"_active": {"extension": [{
"url": "http://example.org/fhir/StructureDefinition/recordStatus",
"valueCode": "archived"
}]},
"name": [
{
"given": [
"Peter",
"James"
],
"use": "official",
"family": ["Chalmers"]
},
{
"given": ["Jim"],
"use": "usual"
}
],
"extension": [
{
"url": "http://example.org/fhir/StructureDefinition/patientAvatar",
"valueReference": {
"reference": "#pic1",
"display": "Duck image"
}
},
{
"url": "http://example.org/fhir/StructureDefinition/complexExtensionExample",
"extension": [
{
"url": "nestedA",
"valueCoding": {
"system": "http://demo.org/id/4",
"code": "AB45",
"extension": [
{
"url": "http://example.org/fhir/StructureDefinition/extraforcodingWithExt",
"extension": [{
"url": "extra1",
"valueString": "extra info"
}]
},
{
"url": "http://example.org/fhir/StructureDefinition/extraforcodingWithValue",
"valueInteger": 45
}
]
}
},
{
"url": "nestedB",
"id": "q4",
"extension": [{
"url": "nestedB1",
"valueString": "hello"
}]
}
]
}
],
"modifierExtension": [
{
"url": "http://example.org/fhir/StructureDefinition/pi",
"valueDecimal": 3.141592653589793
},
{
"url": "http://example.org/fhir/StructureDefinition/avogadro",
"valueDecimal": 6.0221416246424E23
}
],
"gender": "male",
"birthDate": "1974-12",
"deceasedBoolean": true,
"address": [{
"use": "home",
"line": ["534 Erewhon St"],
"city": "PleasantVille",
"state": "Vic",
"postalCode": "3999"
}],
"maritalStatus": {
"coding": [{
"system": "http://hl7.org/fhir/v3/NullFlavor",
"code": "UNK",
"display": "unknown"
}]
},
"multipleBirthInteger": 3,
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n <table>\n <tbody>\n <tr>\n <td>Name<\/td>\n <td>Peter James <b>Chalmers<\/b> (&quot;Jim&quot;)<\/td>\n <\/tr>\n <tr>\n <td>Address<\/td>\n <td>534 Erewhon, Pleasantville, Vic, 3999<\/td>\n <\/tr>\n <tr>\n <td>Contacts<\/td>\n <td>Home: unknown. Work: (03) 5555 6473<\/td>\n <\/tr>\n <tr>\n <td>Id<\/td>\n <td>MRN: 12345 (Acme Healthcare)<\/td>\n <\/tr>\n <\/tbody>\n <\/table>\n <\/div>"
},
"contained": [
{
"resourceType": "Binary",
"id": "pic1",
"contentType": "image/gif",
"content": "R0lGODlhEwARAPcAAAAAAAAA/+9aAO+1AP/WAP/eAP/eCP/eEP/eGP/nAP/nCP/nEP/nIf/nKf/nUv/nWv/vAP/vCP/vEP/vGP/vIf/vKf/vMf/vOf/vWv/vY//va//vjP/3c//3lP/3nP//tf//vf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEAAAEALAAAAAATABEAAAi+AAMIDDCgYMGBCBMSvMCQ4QCFCQcwDBGCA4cLDyEGECDxAoAQHjxwyKhQAMeGIUOSJJjRpIAGDS5wCDly4AALFlYOgHlBwwOSNydM0AmzwYGjBi8IHWoTgQYORg8QIGDAwAKhESI8HIDgwQaRDI1WXXAhK9MBBzZ8/XDxQoUFZC9IiCBh6wEHGz6IbNuwQoSpWxEgyLCXL8O/gAnylNlW6AUEBRIL7Og3KwQIiCXb9HsZQoIEUzUjNEiaNMKAAAA7"
},
{
"resourceType": "Organization",
"id": "org3141",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n <p>Good Health Clinic<\/p>\n <\/div>"
},
"identifier": [{
"system": "urn:ietf:rfc:3986",
"value": "2.16.840.1.113883.19.5"
}],
"name": "Good Health Clinic"
}
],
"contact": [{
"name": {
"family": [
null,
"du",
null,
"Marché",
null
],
"_family": [
{"extension": [{
"url": "http://example.org/fhir/StructureDefinition/nullFlavor",
"valueCode": "ASKU"
}]},
{
"id": "a2",
"extension": [{
"url": "http://example.org/fhir/StructureDefinition/qualifier",
"valueCode": "VV"
}]
},
{"extension": [{
"url": "http://hl7.org/fhir/StructureDefinitioniso-21090#nullFlavor",
"valueCode": "ASKU"
}]},
null,
{"extension": [{
"url": "http://hl7.org/fhir/StructureDefinition/nullFlavor",
"valueCode": "ASKU"
}]}
],
"_given": [
null,
{
"id": "a3",
"extension": [{
"url": "http://hl7.org/fhir/StructureDefinition/qualifier",
"valueCode": "MID"
}]
},
null
],
"given": [
"Bénédicte",
"Denise",
"Marie"
]
},
"relationship": [{"coding": [{
"system": "http://hl7.org/fhir/patient-contact-relationship",
"code": "partner"
}]}],
"telecom": [{
"system": "phone",
"value": "+33 (237) 998327"
}]
}],
"careProvider": [{"reference": "#org3141"}],
"telecom": [
{"use": "home"},
{
"system": "phone",
"value": "(03) 5555 6473",
"use": "work"
}
]
}

View File

@ -416,6 +416,12 @@
In server implementations, the Bundle.entry.fullUrl was not getting correctly
populated on Hl7OrgDstu2 servers. Thanks to Christian Ohr for reporting!
</action>
<action type="fix" issue="335">
Ensure that element IDs within resources (i.e. IDs on elements other than the
resource itself) get serialized and parsed correctly. Previously, these didn't get
serialized in a bunch of circumstances. Thanks to Vadim Peretokin for reporting
and providing test cases!
</action>
</release>
<release version="1.4" date="2016-02-04">
<action type="add">