Fix second part of #216 - Correctly encode choice elements on profiled datatypes
This commit is contained in:
parent
9af3fcf02d
commit
bb5816d8e9
|
@ -24,4 +24,6 @@ public interface IRuntimeDatatypeDefinition {
|
|||
|
||||
boolean isSpecialization();
|
||||
|
||||
public BaseRuntimeElementDefinition<?> getProfileOf();
|
||||
|
||||
}
|
||||
|
|
|
@ -98,7 +98,20 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini
|
|||
|
||||
} else {
|
||||
nextDef = theClassToElementDefinitions.get(next);
|
||||
elementName = getElementName() + StringUtils.capitalize(nextDef.getName());
|
||||
BaseRuntimeElementDefinition<?> nextDefForChoice = nextDef;
|
||||
if (nextDef instanceof IRuntimeDatatypeDefinition) {
|
||||
IRuntimeDatatypeDefinition nextDefDatatype = (IRuntimeDatatypeDefinition) nextDef;
|
||||
if (nextDefDatatype.getProfileOf() != null) {
|
||||
/*
|
||||
* Elements which are called foo[x] and have a choice which is a profiled datatype
|
||||
* must use the unprofiled datatype as the element name. E.g. if foo[x] allows
|
||||
* markdown as a datatype, it calls the element fooString when encoded, because
|
||||
* markdown is a profile of string. This is according to the FHIR spec
|
||||
*/
|
||||
nextDefForChoice = nextDefDatatype.getProfileOf();
|
||||
}
|
||||
}
|
||||
elementName = getElementName() + StringUtils.capitalize(nextDefForChoice.getName());
|
||||
}
|
||||
|
||||
myNameToChildDefinition.put(elementName, nextDef);
|
||||
|
|
|
@ -19,9 +19,12 @@ package ca.uhn.fhir.context;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
@ -30,6 +33,8 @@ import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
|||
public class RuntimeCompositeDatatypeDefinition extends BaseRuntimeElementCompositeDefinition<ICompositeType> implements IRuntimeDatatypeDefinition {
|
||||
|
||||
private boolean mySpecialization;
|
||||
private Class<? extends IBaseDatatype> myProfileOfType;
|
||||
private BaseRuntimeElementDefinition<?> myProfileOf;
|
||||
|
||||
public RuntimeCompositeDatatypeDefinition(DatatypeDef theDef, Class<? extends ICompositeType> theImplementingClass, boolean theStandardType) {
|
||||
super(theDef.name(), theImplementingClass, theStandardType);
|
||||
|
@ -40,9 +45,30 @@ public class RuntimeCompositeDatatypeDefinition extends BaseRuntimeElementCompos
|
|||
}
|
||||
|
||||
mySpecialization = theDef.isSpecialization();
|
||||
myProfileOfType = theDef.profileOf();
|
||||
if (myProfileOfType.equals(IBaseDatatype.class)) {
|
||||
myProfileOfType = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
super.sealAndInitialize(theContext, theClassToElementDefinitions);
|
||||
|
||||
if (myProfileOfType != null) {
|
||||
myProfileOf = theClassToElementDefinitions.get(myProfileOfType);
|
||||
if (myProfileOf == null) {
|
||||
throw new ConfigurationException("Unknown profileOf value: " + myProfileOfType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseRuntimeElementDefinition<?> getProfileOf() {
|
||||
return myProfileOf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpecialization() {
|
||||
return mySpecialization;
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.*;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
@ -32,6 +33,8 @@ import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
|||
|
||||
public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveType<?>> implements IRuntimeDatatypeDefinition {
|
||||
|
||||
private BaseRuntimeElementDefinition<?> myProfileOf;
|
||||
private Class<? extends IBaseDatatype> myProfileOfType;
|
||||
private boolean mySpecialization;
|
||||
|
||||
public RuntimePrimitiveDatatypeDefinition(DatatypeDef theDef, Class<? extends IPrimitiveType<?>> theImplementingClass, boolean theStandardType) {
|
||||
|
@ -43,6 +46,20 @@ public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefini
|
|||
}
|
||||
|
||||
mySpecialization = theDef.isSpecialization();
|
||||
myProfileOfType = theDef.profileOf();
|
||||
if (myProfileOfType.equals(IBaseDatatype.class)) {
|
||||
myProfileOfType = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
|
||||
return ChildTypeEnum.PRIMITIVE_DATATYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseRuntimeElementDefinition<?> getProfileOf() {
|
||||
return myProfileOf;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,12 +69,14 @@ public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefini
|
|||
|
||||
@Override
|
||||
void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
|
||||
return ChildTypeEnum.PRIMITIVE_DATATYPE;
|
||||
super.sealAndInitialize(theContext, theClassToElementDefinitions);
|
||||
|
||||
if (myProfileOfType != null) {
|
||||
myProfileOf = theClassToElementDefinitions.get(myProfileOfType);
|
||||
if (myProfileOf == null) {
|
||||
throw new ConfigurationException("Unknown profileOf value: " + myProfileOfType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||
|
||||
|
@ -49,4 +51,12 @@ public @interface DatatypeDef {
|
|||
*/
|
||||
boolean isSpecialization() default false;
|
||||
|
||||
/**
|
||||
* Indicates that this datatype is a profile of the given datatype, which
|
||||
* implies certain parsing/encoding rules (e.g. a choice element named
|
||||
* foo[x] which allows a Markdown value will still be encoded as
|
||||
* fooString because Markdown is a profile of string.
|
||||
*/
|
||||
Class<? extends IBaseDatatype> profileOf() default IBaseDatatype.class;
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.model.api.BasePrimitive;
|
|||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
|
||||
|
||||
@DatatypeDef(name = "code")
|
||||
@DatatypeDef(name = "code", profileOf=StringDt.class)
|
||||
public class CodeDt extends BasePrimitive<String> implements ICodedDatatype, Comparable<CodeDt> {
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,7 +52,7 @@ import ca.uhn.fhir.util.UrlUtil;
|
|||
* regex: [a-z0-9\-\.]{1,36}
|
||||
* </p>
|
||||
*/
|
||||
@DatatypeDef(name = "id")
|
||||
@DatatypeDef(name = "id", profileOf=StringDt.class)
|
||||
public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
|
||||
|
||||
private String myBaseUrl;
|
||||
|
|
|
@ -23,7 +23,7 @@ package ca.uhn.fhir.model.primitive;
|
|||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
@DatatypeDef(name = "markdown")
|
||||
@DatatypeDef(name = "markdown", profileOf=StringDt.class)
|
||||
@CoverageIgnore
|
||||
public class MarkdownDt extends StringDt {
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ package ca.uhn.fhir.model.primitive;
|
|||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
||||
@DatatypeDef(name = "oid")
|
||||
@DatatypeDef(name = "oid", profileOf=UriDt.class)
|
||||
public class OidDt extends UriDt {
|
||||
|
||||
// TODO: implement restrictions
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
|||
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
@DatatypeDef(name = "positiveInt")
|
||||
@DatatypeDef(name = "positiveInt", profileOf=IntegerDt.class)
|
||||
@CoverageIgnore
|
||||
public class PositiveIntDt extends IntegerDt {
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
|||
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
@DatatypeDef(name = "unsignedInt")
|
||||
@DatatypeDef(name = "unsignedInt", profileOf=IntegerDt.class)
|
||||
@CoverageIgnore
|
||||
public class UnsignedIntDt extends IntegerDt {
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.model.dstu2.composite;
|
|||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -23,7 +24,7 @@ import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@DatatypeDef(name="AgeDt")
|
||||
@DatatypeDef(name="AgeDt", profileOf=QuantityDt.class)
|
||||
public class AgeDt extends QuantityDt {
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@DatatypeDef(name="CountDt")
|
||||
@DatatypeDef(name="CountDt", profileOf=QuantityDt.class)
|
||||
public class CountDt extends QuantityDt {
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.model.dstu2.composite;
|
|||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -23,7 +24,7 @@ import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@DatatypeDef(name="DistanceDt")
|
||||
@DatatypeDef(name="DistanceDt", profileOf=QuantityDt.class)
|
||||
public class DistanceDt extends QuantityDt {
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@DatatypeDef(name="DurationDt")
|
||||
@DatatypeDef(name="DurationDt", profileOf=QuantityDt.class)
|
||||
public class DurationDt extends QuantityDt {
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@DatatypeDef(name="Money")
|
||||
@DatatypeDef(name="Money", profileOf=QuantityDt.class)
|
||||
public class MoneyDt extends QuantityDt {
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@DatatypeDef(name="SimpleQuantity")
|
||||
@DatatypeDef(name="SimpleQuantity", profileOf=QuantityDt.class)
|
||||
public class SimpleQuantityDt extends QuantityDt {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -53,6 +53,7 @@ import ca.uhn.fhir.model.dstu2.composite.ElementDefinitionDt.Binding;
|
|||
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.SimpleQuantityDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.AllergyIntolerance;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Binary;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||
|
@ -63,6 +64,7 @@ import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
|
|||
import ca.uhn.fhir.model.dstu2.resource.Encounter;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Medication;
|
||||
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
|
||||
import ca.uhn.fhir.model.dstu2.resource.MedicationStatement;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
|
@ -214,6 +216,22 @@ public class XmlParserDstu2Test {
|
|||
assertTrue(parsed.getEntries().get(0).getResource().getId().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #216 - Profiled datatypes should use their unprofiled parent type as the choice[x] name
|
||||
*/
|
||||
@Test
|
||||
public void testEncodeAndParseProfiledDatatypeChoice() throws Exception {
|
||||
IParser xmlParser = ourCtx.newXmlParser();
|
||||
|
||||
String input = IOUtils.toString(XmlParser.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
||||
MedicationStatement ms = xmlParser.parseResource(MedicationStatement.class, input);
|
||||
SimpleQuantityDt q = (SimpleQuantityDt) ms.getDosage().get(0).getQuantity();
|
||||
assertEquals("1", q.getValueElement().getValueAsString());
|
||||
|
||||
String output = xmlParser.encodeResourceToString(ms);
|
||||
assertThat(output, containsString("<quantityQuantity><value value=\"1\"/></quantityQuantity>"));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #216
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><MedicationStatement xmlns="http://hl7.org/fhir">
|
||||
<id value="example001"/>
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p>Tylenol No 1 tablet - Taking 1 tablet four times daily as needed for pain</p>
|
||||
</div>
|
||||
</text>
|
||||
<patient>
|
||||
<reference value="Patient/pat1"/>
|
||||
</patient>
|
||||
<informationSource>
|
||||
<reference value="Patient/pat2"/>
|
||||
</informationSource>
|
||||
<dateAsserted value="2015-02-22"/>
|
||||
<status value="completed"/>
|
||||
<wasNotTaken value="false"/>
|
||||
<reasonForUseCodeableConcept>
|
||||
<coding>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="22253000"/>
|
||||
<display value="Pain"/>
|
||||
</coding>
|
||||
</reasonForUseCodeableConcept>
|
||||
<effectiveDateTime value="2015-01-23"/>
|
||||
<note value="Patient indicates they miss the occasional dose"/>
|
||||
<medicationReference> <!-- Linked to a RESOURCE Medication -->
|
||||
<reference value="Medication/MedicationExample7"/>
|
||||
</medicationReference>
|
||||
<dosage>
|
||||
<text value="one tablet four times daily as needed for pain"/>
|
||||
<timing>
|
||||
<repeat>
|
||||
<frequency value="4"/>
|
||||
<period value="1"/>
|
||||
<periodUnits value="d"/>
|
||||
</repeat>
|
||||
</timing>
|
||||
<asNeededBoolean value="true"/>
|
||||
<route>
|
||||
<coding>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="260548002"/>
|
||||
<display value="Oral"/>
|
||||
</coding>
|
||||
</route>
|
||||
<quantityQuantity>
|
||||
<value value="1"/>
|
||||
</quantityQuantity>
|
||||
<maxDosePerPeriod>
|
||||
<numerator>
|
||||
<value value="4"/>
|
||||
<unit value="tablets"/>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="385055001"/>
|
||||
</numerator>
|
||||
<denominator>
|
||||
<value value="1"/>
|
||||
<system value="http://unitsofmeasure.org"/>
|
||||
<code value="d"/>
|
||||
</denominator>
|
||||
</maxDosePerPeriod>
|
||||
</dosage>
|
||||
</MedicationStatement>
|
|
@ -37,7 +37,7 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
/**
|
||||
* A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies.
|
||||
*/
|
||||
@DatatypeDef(name="Age")
|
||||
@DatatypeDef(name="Age", profileOf=Quantity.class)
|
||||
public class Age extends Quantity {
|
||||
|
||||
private static final long serialVersionUID = 1069574054L;
|
||||
|
|
|
@ -35,8 +35,8 @@ import org.hl7.fhir.instance.model.annotations.DatatypeDef;
|
|||
/**
|
||||
* Primitive type "code" in FHIR, when not bound to an enumerated list of codes
|
||||
*/
|
||||
@DatatypeDef(name="code")
|
||||
public class CodeType extends PrimitiveType<String> implements Comparable<CodeType> {
|
||||
@DatatypeDef(name="code", profileOf=StringType.class)
|
||||
public class CodeType extends StringType implements Comparable<CodeType> {
|
||||
|
||||
private static final long serialVersionUID = 3L;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
/**
|
||||
* A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies.
|
||||
*/
|
||||
@DatatypeDef(name="Count")
|
||||
@DatatypeDef(name="Count", profileOf=Quantity.class)
|
||||
public class Count extends Quantity {
|
||||
|
||||
private static final long serialVersionUID = 1069574054L;
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
/**
|
||||
* A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies.
|
||||
*/
|
||||
@DatatypeDef(name="Distance")
|
||||
@DatatypeDef(name="Distance", profileOf=Quantity.class)
|
||||
public class Distance extends Quantity {
|
||||
|
||||
private static final long serialVersionUID = 1069574054L;
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
/**
|
||||
* A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies.
|
||||
*/
|
||||
@DatatypeDef(name="Duration")
|
||||
@DatatypeDef(name="Duration", profileOf=Quantity.class)
|
||||
public class Duration extends Quantity {
|
||||
|
||||
private static final long serialVersionUID = 1069574054L;
|
||||
|
|
|
@ -81,7 +81,7 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|||
* Regex for ID: [a-z0-9\-\.]{1,36}
|
||||
* </p>
|
||||
*/
|
||||
@DatatypeDef(name = "id")
|
||||
@DatatypeDef(name = "id", profileOf=Type.class)
|
||||
public final class IdType extends UriType implements IPrimitiveType<String>, IIdType {
|
||||
/**
|
||||
* This is the maximum length for the ID
|
||||
|
|
|
@ -35,8 +35,8 @@ import org.hl7.fhir.instance.model.annotations.DatatypeDef;
|
|||
/**
|
||||
* Primitive type "code" in FHIR, when not bound to an enumerated list of codes
|
||||
*/
|
||||
@DatatypeDef(name="markdown")
|
||||
public class MarkdownType extends PrimitiveType<String> implements Comparable<MarkdownType> {
|
||||
@DatatypeDef(name="markdown", profileOf=StringType.class)
|
||||
public class MarkdownType extends StringType implements Comparable<MarkdownType> {
|
||||
|
||||
private static final long serialVersionUID = 3L;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
/**
|
||||
* A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies.
|
||||
*/
|
||||
@DatatypeDef(name="Money")
|
||||
@DatatypeDef(name="Money", profileOf=Quantity.class)
|
||||
public class Money extends Quantity {
|
||||
|
||||
private static final long serialVersionUID = 1069574054L;
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.hl7.fhir.instance.model.annotations.DatatypeDef;
|
|||
/**
|
||||
* Primitive type "oid" in FHIR: an OID represented as urn:oid:0.1.2.3.4...
|
||||
*/
|
||||
@DatatypeDef(name="oid")
|
||||
@DatatypeDef(name="oid", profileOf=UriType.class)
|
||||
public class OidType extends UriType {
|
||||
|
||||
private static final long serialVersionUID = 3L;
|
||||
|
|
|
@ -36,7 +36,7 @@ import org.hl7.fhir.instance.model.annotations.DatatypeDef;
|
|||
/**
|
||||
* Primitive type "integer" in FHIR: A signed 32-bit integer
|
||||
*/
|
||||
@DatatypeDef(name = "positiveInt")
|
||||
@DatatypeDef(name = "positiveInt", profileOf=IntegerType.class)
|
||||
public class PositiveIntType extends IntegerType {
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
/**
|
||||
* A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies.
|
||||
*/
|
||||
@DatatypeDef(name="SimpleQuantity")
|
||||
@DatatypeDef(name="SimpleQuantity", profileOf=Quantity.class)
|
||||
public class SimpleQuantity extends Quantity {
|
||||
|
||||
private static final long serialVersionUID = 1069574054L;
|
||||
|
|
|
@ -36,7 +36,7 @@ import org.hl7.fhir.instance.model.annotations.DatatypeDef;
|
|||
/**
|
||||
* Primitive type "integer" in FHIR: A signed 32-bit integer
|
||||
*/
|
||||
@DatatypeDef(name = "unsignedInt")
|
||||
@DatatypeDef(name = "unsignedInt", profileOf=IntegerType.class)
|
||||
public class UnsignedIntType extends IntegerType {
|
||||
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
|
||||
/**
|
||||
* Class annotation to note a class which defines a datatype
|
||||
*/
|
||||
|
@ -75,4 +77,12 @@ public @interface DatatypeDef {
|
|||
*/
|
||||
boolean isSpecialization() default false;
|
||||
|
||||
/**
|
||||
* Indicates that this datatype is a profile of the given datatype, which
|
||||
* implies certain parsing/encoding rules (e.g. a choice element named
|
||||
* foo[x] which allows a Markdown value will still be encoded as
|
||||
* fooString because Markdown is a profile of string.
|
||||
*/
|
||||
Class<? extends IBaseDatatype> profileOf() default IBaseDatatype.class;
|
||||
|
||||
}
|
||||
|
|
|
@ -129,15 +129,16 @@ public class BaseValidator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#INFORMATION} validation message if the validation fails
|
||||
* Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails
|
||||
*
|
||||
* @param thePass
|
||||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
|
||||
protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass) {
|
||||
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.INFORMATION));
|
||||
String message = formatMessage(theMessage, theMessageArguments);
|
||||
errors.add(new ValidationMessage(source, type, line, col, path, message, IssueSeverity.INFORMATION));
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
@ -158,6 +159,20 @@ public class BaseValidator {
|
|||
return thePass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#INFORMATION} validation message if the validation fails
|
||||
*
|
||||
* @param thePass
|
||||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
|
||||
if (!thePass) {
|
||||
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.INFORMATION));
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails
|
||||
*
|
||||
|
@ -165,9 +180,10 @@ public class BaseValidator {
|
|||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean rule(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg) {
|
||||
protected boolean rule(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass) {
|
||||
errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.ERROR));
|
||||
String message = formatMessage(theMessage, theMessageArguments);
|
||||
errors.add(new ValidationMessage(source, type, line, col, path, message, IssueSeverity.ERROR));
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
@ -203,13 +219,6 @@ public class BaseValidator {
|
|||
return thePass;
|
||||
}
|
||||
|
||||
private String toPath(List<String> pathParts) {
|
||||
if (pathParts == null || pathParts.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return "//" + StringUtils.join(pathParts, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails
|
||||
*
|
||||
|
@ -259,6 +268,13 @@ public class BaseValidator {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
private String toPath(List<String> pathParts) {
|
||||
if (pathParts == null || pathParts.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return "//" + StringUtils.join(pathParts, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
|
||||
*
|
||||
|
@ -275,6 +291,22 @@ public class BaseValidator {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
|
||||
*
|
||||
* @param thePass
|
||||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warning(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass) {
|
||||
String path = toPath(pathParts);
|
||||
String message = formatMessage(theMessage, theMessageArguments);
|
||||
errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.WARNING));
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
|
||||
*
|
||||
|
@ -318,20 +350,4 @@ public class BaseValidator {
|
|||
return thePass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
|
||||
*
|
||||
* @param thePass
|
||||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warning(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass) {
|
||||
String path = toPath(pathParts);
|
||||
String message = formatMessage(theMessage, theMessageArguments);
|
||||
errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.WARNING));
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1699,17 +1699,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
ElementDefinitionBindingComponent binding = context.getBinding();
|
||||
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
||||
ValueSet vs = resolveBindingReference(binding.getValueSet());
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "ValueSet "+describeReference(binding.getValueSet())+" not found")) {
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "ValueSet {0} not found", describeReference(binding.getValueSet()))) {
|
||||
try {
|
||||
vs = cache.getExpander().expand(vs).getValueset();
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "Unable to expand value set for "+describeReference(binding.getValueSet()))) {
|
||||
ValueSetExpansionOutcome expansionOutcome = cache.getExpander().expand(vs);
|
||||
vs = expansionOutcome != null ? expansionOutcome.getValueset() : null;
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "Unable to expand value set for {0}", describeReference(binding.getValueSet()))) {
|
||||
boolean ok = codeInExpansion(vs, null, value);
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||
rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, ok, "Coded value "+value+" is not in value set "+describeReference(binding.getValueSet())+" ("+vs.getUrl()+")");
|
||||
rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, ok, "Coded value {0} is not in value set {1} ({2})", value, describeReference(binding.getValueSet()), vs.getUrl());
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, ok, "Coded value "+value+" is not in value set "+describeReference(binding.getValueSet())+" ("+vs.getUrl()+")");
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, ok, "Coded value {0} is not in value set {1} ({2})", value, describeReference(binding.getValueSet()), vs.getUrl());
|
||||
else
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, ok, "Coded value "+value+" is not in value set "+describeReference(binding.getValueSet())+" ("+vs.getUrl()+")");
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, ok, "Coded value {0} is not in value set {1} ({2})", value, describeReference(binding.getValueSet()), vs.getUrl());
|
||||
}
|
||||
} catch (ETooCostly e) {
|
||||
if (e.getMessage() == null)
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.hl7.fhir.instance.model.Base;
|
|||
import org.hl7.fhir.instance.model.Binary;
|
||||
import org.hl7.fhir.instance.model.BooleanType;
|
||||
import org.hl7.fhir.instance.model.Bundle;
|
||||
import org.hl7.fhir.instance.model.CodeType;
|
||||
import org.hl7.fhir.instance.model.Coding;
|
||||
import org.hl7.fhir.instance.model.DecimalType;
|
||||
import org.hl7.fhir.instance.model.DomainResource;
|
||||
|
@ -24,40 +25,43 @@ import org.hl7.fhir.instance.model.Identifier.IdentifierUseEnumFactory;
|
|||
import org.hl7.fhir.instance.model.IntegerType;
|
||||
import org.hl7.fhir.instance.model.List_;
|
||||
import org.hl7.fhir.instance.model.Meta;
|
||||
import org.hl7.fhir.instance.model.Money;
|
||||
import org.hl7.fhir.instance.model.Narrative;
|
||||
import org.hl7.fhir.instance.model.Parameters;
|
||||
import org.hl7.fhir.instance.model.PrimitiveType;
|
||||
import org.hl7.fhir.instance.model.Quantity;
|
||||
import org.hl7.fhir.instance.model.Reference;
|
||||
import org.hl7.fhir.instance.model.Resource;
|
||||
import org.hl7.fhir.instance.model.StringType;
|
||||
import org.hl7.fhir.instance.model.Timing;
|
||||
import org.hl7.fhir.instance.model.Type;
|
||||
import org.hl7.fhir.instance.model.annotations.Block;
|
||||
import org.hl7.fhir.instance.model.annotations.Child;
|
||||
import org.hl7.fhir.instance.model.annotations.DatatypeDef;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatypeElement;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseEnumeration;
|
||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IBaseIntegerDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseXhtml;
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatypeElement;
|
||||
import org.hl7.fhir.instance.model.api.IDomainResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.INarrative;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -153,7 +157,15 @@ public class ModelInheritanceTest {
|
|||
assertTrue(IBase.class.isAssignableFrom(Base.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testProfiledDatatype() {
|
||||
assertEquals(StringType.class, CodeType.class.getSuperclass());
|
||||
assertEquals(StringType.class, CodeType.class.getAnnotation(DatatypeDef.class).profileOf());
|
||||
assertEquals(Quantity.class, Money.class.getSuperclass());
|
||||
assertEquals(Quantity.class, Money.class.getAnnotation(DatatypeDef.class).profileOf());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBinary() {
|
||||
assertTrue(IBaseBinary.class.isAssignableFrom(Binary.class));
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
@ -39,6 +46,7 @@ import org.hl7.fhir.instance.model.HumanName;
|
|||
import org.hl7.fhir.instance.model.Identifier;
|
||||
import org.hl7.fhir.instance.model.Identifier.IdentifierUse;
|
||||
import org.hl7.fhir.instance.model.InstantType;
|
||||
import org.hl7.fhir.instance.model.MedicationStatement;
|
||||
import org.hl7.fhir.instance.model.Narrative.NarrativeStatus;
|
||||
import org.hl7.fhir.instance.model.Observation;
|
||||
import org.hl7.fhir.instance.model.Organization;
|
||||
|
@ -46,6 +54,7 @@ import org.hl7.fhir.instance.model.Patient;
|
|||
import org.hl7.fhir.instance.model.PrimitiveType;
|
||||
import org.hl7.fhir.instance.model.Reference;
|
||||
import org.hl7.fhir.instance.model.Resource;
|
||||
import org.hl7.fhir.instance.model.SimpleQuantity;
|
||||
import org.hl7.fhir.instance.model.Specimen;
|
||||
import org.hl7.fhir.instance.model.StringType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -78,6 +87,23 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
return htmlNoNs.replace("<div>", "<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">");
|
||||
}
|
||||
|
||||
/**
|
||||
* See #216 - Profiled datatypes should use their unprofiled parent type as the choice[x] name
|
||||
*/
|
||||
@Test
|
||||
public void testEncodeAndParseProfiledDatatypeChoice() throws Exception {
|
||||
IParser xmlParser = ourCtx.newXmlParser();
|
||||
|
||||
String input = IOUtils.toString(XmlParser.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
||||
MedicationStatement ms = xmlParser.parseResource(MedicationStatement.class, input);
|
||||
SimpleQuantity q = (SimpleQuantity) ms.getDosage().get(0).getQuantity();
|
||||
assertEquals("1", q.getValueElement().getValueAsString());
|
||||
|
||||
String output = xmlParser.encodeResourceToString(ms);
|
||||
assertThat(output, containsString("<quantityQuantity><value value=\"1\"/></quantityQuantity>"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testComposition() {
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.instance.model.CodeType;
|
||||
import org.hl7.fhir.instance.model.Observation;
|
||||
import org.hl7.fhir.instance.model.Observation.ObservationStatus;
|
||||
|
@ -25,8 +25,6 @@ import org.mockito.invocation.InvocationOnMock;
|
|||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
|
||||
public class FhirInstanceValidatorTest {
|
||||
|
||||
|
@ -199,6 +197,19 @@ public class FhirInstanceValidatorTest {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #216
|
||||
*/
|
||||
@Test
|
||||
public void testValidateRawXmlInvalidChoiceName() throws Exception {
|
||||
String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
|
||||
List<SingleValidationMessage> res = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertEquals(output.toString(), 0, res.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateResourceContainingProfileDeclarationDoesntResolve() {
|
||||
addValidConcept("http://loinc.org", "12345");
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><MedicationStatement xmlns="http://hl7.org/fhir">
|
||||
<id value="example001"/>
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p>Tylenol No 1 tablet - Taking 1 tablet four times daily as needed for pain</p>
|
||||
</div>
|
||||
</text>
|
||||
<patient>
|
||||
<reference value="Patient/pat1"/>
|
||||
</patient>
|
||||
<informationSource>
|
||||
<reference value="Patient/pat2"/>
|
||||
</informationSource>
|
||||
<dateAsserted value="2015-02-22"/>
|
||||
<status value="completed"/>
|
||||
<wasNotTaken value="false"/>
|
||||
<reasonForUseCodeableConcept>
|
||||
<coding>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="22253000"/>
|
||||
<display value="Pain"/>
|
||||
</coding>
|
||||
</reasonForUseCodeableConcept>
|
||||
<effectiveDateTime value="2015-01-23"/>
|
||||
<note value="Patient indicates they miss the occasional dose"/>
|
||||
<medicationReference> <!-- Linked to a RESOURCE Medication -->
|
||||
<reference value="Medication/MedicationExample7"/>
|
||||
</medicationReference>
|
||||
<dosage>
|
||||
<text value="one tablet four times daily as needed for pain"/>
|
||||
<timing>
|
||||
<repeat>
|
||||
<frequency value="4"/>
|
||||
<period value="1"/>
|
||||
<periodUnits value="d"/>
|
||||
</repeat>
|
||||
</timing>
|
||||
<asNeededBoolean value="true"/>
|
||||
<route>
|
||||
<coding>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="260548002"/>
|
||||
<display value="Oral"/>
|
||||
</coding>
|
||||
</route>
|
||||
<quantityQuantity>
|
||||
<value value="1"/>
|
||||
</quantityQuantity>
|
||||
<maxDosePerPeriod>
|
||||
<numerator>
|
||||
<value value="4"/>
|
||||
<unit value="tablets"/>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="385055001"/>
|
||||
</numerator>
|
||||
<denominator>
|
||||
<value value="1"/>
|
||||
<system value="http://unitsofmeasure.org"/>
|
||||
<code value="d"/>
|
||||
</denominator>
|
||||
</maxDosePerPeriod>
|
||||
</dosage>
|
||||
</MedicationStatement>
|
|
@ -189,6 +189,7 @@
|
|||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<!-- TODO: add search.maven.org links to these -->
|
||||
<b>hapi-fhir-structures-hl7org-dstu2</b>
|
||||
: This file contains the "reference implementation"
|
||||
structures and tooling. You need to include it even if you are not using the RI model
|
||||
|
|
Loading…
Reference in New Issue