Sync DSTU2 validator with RI
This commit is contained in:
parent
efe9cd1dd1
commit
35ffbf1568
|
@ -183,6 +183,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
|||
myDaoConfig.setHardSearchLimit(1000);
|
||||
myDaoConfig.setHardTagListLimit(1000);
|
||||
myDaoConfig.setIncludeLimit(2000);
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
|
@ -41,6 +42,7 @@ import org.apache.http.entity.StringEntity;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
|
@ -2185,6 +2187,53 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* From example from david hay - moved to the hl7org_dstu2 project
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateDavidsAllergyIntolerance() throws Exception {
|
||||
myDaoConfig.setAllowExternalReferences(true);
|
||||
|
||||
/*
|
||||
* Upload structurredef
|
||||
*/
|
||||
|
||||
String contents = IOUtils.toString(getClass().getResourceAsStream("/allergyintolerance-sd-david.json"), "UTF-8");
|
||||
HttpEntityEnclosingRequestBase post = new HttpPut(ourServerBase + "/StructureDefinition/ohAllergyIntolerance");
|
||||
post.setEntity(new StringEntity(contents, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent());
|
||||
ourLog.info(resp);
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
response.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate
|
||||
*/
|
||||
|
||||
contents = IOUtils.toString(getClass().getResourceAsStream("/allergyintolerance-david.json"), "UTF-8");
|
||||
|
||||
post = new HttpPost(ourServerBase + "/AllergyIntolerance/$validate?_pretty=true");
|
||||
post.setEntity(new StringEntity(contents, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||
|
||||
response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent());
|
||||
ourLog.info(resp);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
assertThat(resp, not(containsString("Resource has no id")));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValidateResourceHuge() throws IOException {
|
||||
|
@ -2318,4 +2367,5 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"resourceType": "AllergyIntolerance",
|
||||
"id": "84651",
|
||||
"meta": {
|
||||
"versionId": "1",
|
||||
"lastUpdated": "2016-05-19T15:43:49.815-04:00",
|
||||
"profile": [
|
||||
"http://fhir.hl7.org.nz/dstu2/StructureDefinition/ohAllergyIntolerance"
|
||||
]
|
||||
},
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-endDate",
|
||||
"valueDateTime": "2016-05-03"
|
||||
},
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-informantRole",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "133932002",
|
||||
"display": "Carer"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-reasonClosed",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/adverse-reaction-reason-closed",
|
||||
"code": "1",
|
||||
"display": "Disproven"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-classification",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "419076005",
|
||||
"display": "Allergic reaction"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"language": [
|
||||
"en"
|
||||
],
|
||||
"identifier": [
|
||||
{
|
||||
"system": "http://orionhealth.com/identifier/problem-list/ORGNISATION_ORION",
|
||||
"value": "2.25.148135789146703435349240718177383549558.8.4.4.0/522911"
|
||||
}
|
||||
],
|
||||
"patient": {
|
||||
"reference": "Patient/64909"
|
||||
},
|
||||
"substance": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "84430008",
|
||||
"display": "Cross reacting antibody"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": "inactive",
|
||||
"criticality": "CRITH",
|
||||
"category": "environment",
|
||||
"reaction": [
|
||||
{
|
||||
"certainty": "likely",
|
||||
"_certainty": {
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/originalValue",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/adverse-reaction-certainty",
|
||||
"code": "SUSPECTED",
|
||||
"display": "Suspected"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"manifestation": [
|
||||
{
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-manifestationSeverity",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/900000000000207008/version/20150531",
|
||||
"code": "442452003",
|
||||
"display": "Life-Threatening"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/clinical-manifestation",
|
||||
"code": "FT",
|
||||
"display": "rlo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-manifestationSeverity",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/severity",
|
||||
"code": "UNKNOWN",
|
||||
"display": "Unknown"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "95332009",
|
||||
"display": "Rash of systemic lupus erythematosus"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"severity": "severe"
|
||||
}
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -83,7 +83,6 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
myValidConcepts.add(theSystem + "___" + theCode);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
// @Ignore
|
||||
public void testValidateBuiltInProfiles() throws Exception {
|
||||
|
@ -94,7 +93,7 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
vsContents = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/org/hl7/fhir/instance/model/dstu3/profile/" + name + ".xml"), "UTF-8");
|
||||
|
||||
TreeSet<String> ids = new TreeSet<String>();
|
||||
|
||||
|
||||
bundle = ourCtx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
|
||||
for (BundleEntryComponent i : bundle.getEntry()) {
|
||||
org.hl7.fhir.dstu3.model.Resource next = i.getResource();
|
||||
|
@ -126,28 +125,28 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
@Ignore
|
||||
public void testValidateBundleWithObservations() throws Exception {
|
||||
String name = "profiles-resources";
|
||||
ourLog.info("Uploading " + name);
|
||||
String inputString;
|
||||
inputString = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/brian_reinhold_bundle.json"), "UTF-8");
|
||||
Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, inputString);
|
||||
|
||||
|
||||
FHIRPathEngine fp = new FHIRPathEngine(new HapiWorkerContext(ourCtx, myDefaultValidationSupport));
|
||||
List<Base> fpOutput;
|
||||
BooleanType bool;
|
||||
|
||||
|
||||
fpOutput = fp.evaluate(bundle.getEntry().get(0).getResource(), "component.where(code = %resource.code).empty()");
|
||||
assertEquals(1, fpOutput.size());
|
||||
bool = (BooleanType) fpOutput.get(0);
|
||||
assertTrue(bool.getValue());
|
||||
//
|
||||
// fpOutput = fp.evaluate(bundle, "component.where(code = %resource.code).empty()");
|
||||
// assertEquals(1, fpOutput.size());
|
||||
// bool = (BooleanType) fpOutput.get(0);
|
||||
// assertTrue(bool.getValue());
|
||||
|
||||
//
|
||||
// fpOutput = fp.evaluate(bundle, "component.where(code = %resource.code).empty()");
|
||||
// assertEquals(1, fpOutput.size());
|
||||
// bool = (BooleanType) fpOutput.get(0);
|
||||
// assertTrue(bool.getValue());
|
||||
|
||||
ValidationResult output = myVal.validateWithResult(inputString);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(errors, empty());
|
||||
|
@ -266,8 +265,7 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
|
||||
int index = 0;
|
||||
for (SingleValidationMessage next : theOutput.getMessages()) {
|
||||
ourLog.info("Result {}: {} - {}:{} {} - {}",
|
||||
new Object[] { index, next.getSeverity(), defaultString(next.getLocationLine()), defaultString(next.getLocationCol()), next.getLocationString(), next.getMessage() });
|
||||
ourLog.info("Result {}: {} - {}:{} {} - {}", new Object[] { index, next.getSeverity(), defaultString(next.getLocationLine()), defaultString(next.getLocationCol()), next.getLocationString(), next.getMessage() });
|
||||
index++;
|
||||
|
||||
retVal.add(next);
|
||||
|
@ -482,12 +480,9 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testValidateResourceWithDefaultValuesetBadCode() {
|
||||
String input = "<Observation xmlns=\"http://hl7.org/fhir\">\n" + " <status value=\"notvalidcode\"/>\n" + " <code>\n" + " <text value=\"No code here!\"/>\n" + " </code>\n"
|
||||
+ "</Observation>";
|
||||
String input = "<Observation xmlns=\"http://hl7.org/fhir\">\n" + " <status value=\"notvalidcode\"/>\n" + " <code>\n" + " <text value=\"No code here!\"/>\n" + " </code>\n" + "</Observation>";
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
assertEquals(
|
||||
"The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status, and a code is required from this value set",
|
||||
output.getMessages().get(0).getMessage());
|
||||
assertEquals("The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status, and a code is required from this value set", output.getMessages().get(0).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -565,9 +560,7 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
List<SingleValidationMessage> all = logResultsAndReturnAll(output);
|
||||
assertEquals(1, all.size());
|
||||
assertEquals("Patient.identifier.type", all.get(0).getLocationString());
|
||||
assertEquals(
|
||||
"None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type, and a code should come from this value set unless it has no suitable code",
|
||||
all.get(0).getMessage());
|
||||
assertEquals("None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type, and a code should come from this value set unless it has no suitable code", all.get(0).getMessage());
|
||||
assertEquals(ResultSeverityEnum.WARNING, all.get(0).getSeverity());
|
||||
|
||||
}
|
||||
|
|
|
@ -154,6 +154,8 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
|
||||
v.setBestPracticeWarningLevel(myBestPracticeWarningLevel);
|
||||
v.setAnyExtensionsAllowed(true);
|
||||
v.setRequireResourceId(false);
|
||||
v.setSuppressLoincSnomedMessages(true);
|
||||
|
||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
|
||||
|
|
|
@ -39,11 +39,11 @@ import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
|||
import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.instance.terminologies.ValueSetExpander.ETooCostly;
|
||||
import org.hl7.fhir.instance.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.instance.terminologies.ValueSetExpanderFactory;
|
||||
import org.hl7.fhir.instance.terminologies.ValueSetExpansionCache;
|
||||
import org.hl7.fhir.instance.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.instance.utilities.Utilities;
|
||||
import org.hl7.fhir.instance.utilities.xml.XMLUtil;
|
||||
import org.hl7.fhir.instance.terminologies.ValueSetExpanderFactory;
|
||||
import org.hl7.fhir.instance.terminologies.ValueSetExpansionCache;
|
||||
import org.hl7.fhir.instance.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.instance.utils.IWorkerContext;
|
||||
import org.hl7.fhir.instance.utils.IWorkerContext.ValidationResult;
|
||||
|
@ -59,7 +59,6 @@ import com.google.gson.JsonNull;
|
|||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
|
||||
/*
|
||||
* todo:
|
||||
* check urn's don't start oid: or uuid:
|
||||
|
@ -69,6 +68,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean anyExtensionsAllowed;
|
||||
|
||||
private BestPracticeWarningLevel bpWarnings;
|
||||
private ValueSetExpanderFactory cache;
|
||||
// configuration items
|
||||
private CheckDisplayOption checkDisplay;
|
||||
private IWorkerContext context;
|
||||
|
@ -84,6 +84,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
super();
|
||||
this.context = theContext;
|
||||
source = Source.InstanceValidator;
|
||||
cache = new ValueSetExpansionCache(theContext, null);
|
||||
}
|
||||
|
||||
public InstanceValidator(IWorkerContext theContext, ValueSetExpanderFactory theValueSetExpander) throws Exception {
|
||||
super();
|
||||
this.context = theContext;
|
||||
source = Source.InstanceValidator;
|
||||
this.cache = theValueSetExpander;
|
||||
}
|
||||
|
||||
private boolean allowUnknownExtension(String url) {
|
||||
|
@ -185,35 +193,71 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
|
||||
private void checkCodeableConcept(List<ValidationMessage> errors, String path, WrapperElement element, StructureDefinition profile, ElementDefinition theElementCntext) throws EOperationOutcome, Exception {
|
||||
private void checkCodeableConcept(List<ValidationMessage> errors, String path, WrapperElement element, StructureDefinition profile, ElementDefinition theElementCntext)
|
||||
throws EOperationOutcome, Exception {
|
||||
if (theElementCntext != null && theElementCntext.hasBinding()) {
|
||||
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, "Binding for " + path + " missing (cc)")) {
|
||||
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
||||
ValueSet valueset = resolveBindingReference(binding.getValueSet());
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
||||
CodeableConcept cc = null;
|
||||
try {
|
||||
cc = readAsCodeableConcept(element);
|
||||
if (!cc.hasCoding()) {
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||
rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "No code provided, and a code is required from the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl());
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "No code provided, and a code should be provided from the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl());
|
||||
} else {
|
||||
ValidationResult vr = context.validateCode(cc, valueset);
|
||||
if (!vr.isOk()) {
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||
rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "None of the codes provided are in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl()+", and a code from this value set is required");
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "None of the codes provided are in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code should come from this value set unless it has no suitable code");
|
||||
else if (binding.getStrength() == BindingStrength.PREFERRED)
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "None of the codes provided are in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code is recommended to come from this value set");
|
||||
ValueSet unexpandedVs = resolveBindingReference(binding.getValueSet());
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, unexpandedVs != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
||||
ValueSet vs;
|
||||
try {
|
||||
boolean found = false;
|
||||
boolean any = false;
|
||||
WrapperElement c = element.getFirstChild();
|
||||
while (c != null) {
|
||||
if (c.getName().equals("coding")) {
|
||||
any = true;
|
||||
String system = c.getNamedChildValue("system");
|
||||
String code = c.getNamedChildValue("code");
|
||||
if (system != null && code != null) {
|
||||
ValueSetExpansionOutcome exp = cache.getExpander().expand(unexpandedVs);
|
||||
vs = exp != null ? exp.getValueset() : null;
|
||||
if (vs == null) {
|
||||
if (binding.getStrength() != BindingStrength.REQUIRED) {
|
||||
ValidationResult validationResult = context.validateCode(system, code, null);
|
||||
if (validationResult.isOk()) {
|
||||
found = true;
|
||||
} else {
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Unable to validate code \"{0}\" in code system \"{1}\"", code, system);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
if (!warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "Unable to expand value set for " + describeReference(binding.getValueSet()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
found = found || codeInExpansion(vs, system, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Error "+e.getMessage()+" validating CodeableConcept");
|
||||
}
|
||||
c = c.getNextSibling();
|
||||
}
|
||||
if (!any && binding.getStrength() == BindingStrength.REQUIRED)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, found,
|
||||
"No code provided, and value set " + describeReference(binding.getValueSet()) + " (" + unexpandedVs.getUrl() + ") is required");
|
||||
if (any)
|
||||
if (binding.getStrength() == BindingStrength.PREFERRED)
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, found,
|
||||
"None of the codes are in the example value set " + describeReference(binding.getValueSet()) + " (" + unexpandedVs.getUrl() + ")");
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, found,
|
||||
"None of the codes are in the expected value set " + describeReference(binding.getValueSet()) + " (" + unexpandedVs.getUrl() + ")");
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage() == null) {
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false,
|
||||
"Exception opening value set " + unexpandedVs.getUrl() + " for " + describeReference(binding.getValueSet()) + ": --Null--");
|
||||
// } else if (!e.getMessage().contains("unable to find value set http://snomed.info/sct")) {
|
||||
// hint(errors, IssueType.CODEINVALID, path, suppressLoincSnomedMessages, "Snomed value set - not validated");
|
||||
// } else if (!e.getMessage().contains("unable to find value set http://loinc.org")) {
|
||||
// hint(errors, IssueType.CODEINVALID, path, suppressLoincSnomedMessages, "Loinc value set - not validated");
|
||||
} else
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false,
|
||||
"Exception opening value set " + unexpandedVs.getUrl() + " for " + describeReference(binding.getValueSet()) + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} else if (binding.hasValueSet()) {
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding by URI reference cannot be checked");
|
||||
|
@ -224,33 +268,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
|
||||
private CodeableConcept readAsCodeableConcept(WrapperElement element) {
|
||||
CodeableConcept cc = new CodeableConcept();
|
||||
List<WrapperElement> list = new ArrayList<WrapperElement>();
|
||||
element.getNamedChildren("coding", list);
|
||||
for (WrapperElement item : list)
|
||||
cc.addCoding(readAsCoding(item));
|
||||
cc.setText(element.getNamedChildValue("text"));
|
||||
return cc;
|
||||
}
|
||||
|
||||
private Coding readAsCoding(WrapperElement item) {
|
||||
Coding c = new Coding();
|
||||
c.setSystem(item.getNamedChildValue("system"));
|
||||
c.setVersion(item.getNamedChildValue("version"));
|
||||
c.setCode(item.getNamedChildValue("code"));
|
||||
c.setDisplay(item.getNamedChildValue("display"));
|
||||
return c;
|
||||
}
|
||||
|
||||
private void checkCoding(List<ValidationMessage> errors, String path, WrapperElement focus, Coding fixed) {
|
||||
private void checkCoding(List<ValidationMessage> errors, String path, WrapperElement focus, Coding fixed) {
|
||||
checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), "system");
|
||||
checkFixedValue(errors, path + ".code", focus.getNamedChild("code"), fixed.getCodeElement(), "code");
|
||||
checkFixedValue(errors, path + ".display", focus.getNamedChild("display"), fixed.getDisplayElement(), "display");
|
||||
checkFixedValue(errors, path + ".userSelected", focus.getNamedChild("userSelected"), fixed.getUserSelectedElement(), "userSelected");
|
||||
}
|
||||
|
||||
private void checkCoding(List<ValidationMessage> errors, String path, WrapperElement element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept) throws EOperationOutcome, Exception {
|
||||
private void checkCoding(List<ValidationMessage> errors, String path, WrapperElement element, StructureDefinition profile, ElementDefinition context) throws EOperationOutcome, Exception {
|
||||
String code = element.getNamedChildValue("code");
|
||||
String system = element.getNamedChildValue("system");
|
||||
String display = element.getNamedChildValue("display");
|
||||
|
@ -258,31 +283,37 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
if (system != null && code != null) {
|
||||
if (checkCode(errors, element, path, code, system, display))
|
||||
if (theElementCntext != null && theElementCntext.getBinding() != null) {
|
||||
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
||||
if (context != null && context.getBinding() != null) {
|
||||
ElementDefinitionBindingComponent binding = context.getBinding();
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, "Binding for " + path + " missing")) {
|
||||
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
||||
ValueSet valueset = resolveBindingReference(binding.getValueSet());
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
||||
Coding c = null;
|
||||
try {
|
||||
c = readAsCoding(element);
|
||||
ValidationResult vr = context.validateCode(c, valueset);
|
||||
if (!vr.isOk()) {
|
||||
ValueSet vs = resolveBindingReference(binding.getValueSet());
|
||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
||||
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()))) {
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code is required from this value set");
|
||||
rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, codeInExpansion(vs, system, code),
|
||||
"Code {" + system + "}" + code + " is not in value set " + describeReference(binding.getValueSet()) + " (" + vs.getUrl() + ")");
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code should come from this value set unless it has no suitable code");
|
||||
else if (binding.getStrength() == BindingStrength.PREFERRED)
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code is recommended to come from this value set");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Error "+e.getMessage()+" validating CodeableConcept");
|
||||
}
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, codeInExpansion(vs, system, code),
|
||||
"Code {" + system + "}" + code + " is not in value set " + describeReference(binding.getValueSet()) + " (" + vs.getUrl() + ")");
|
||||
else
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, codeInExpansion(vs, system, code),
|
||||
"Code {" + system + "}" + code + " is not in value set " + describeReference(binding.getValueSet()) + " (" + vs.getUrl() + ")");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage() == null)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false,
|
||||
"Exception opening value set " + vs.getUrl() + " for " + describeReference(binding.getValueSet()) + ": --Null--");
|
||||
else
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false,
|
||||
"Exception opening value set " + vs.getUrl() + " for " + describeReference(binding.getValueSet()) + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} else if (binding.hasValueSet()) {
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding by URI reference cannot be checked");
|
||||
} else if (!inCodeableConcept) {
|
||||
} else {
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding for path " + path + " has no source, so can't be checked");
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +343,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (warning(errors, IssueType.INVALID, element.line(), element.col(), p, pr != null, "StructureDefinition reference \"{0}\" could not be resolved", ref)) {
|
||||
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), p, pr.hasSnapshot(),
|
||||
"StructureDefinition has no snapshot - validation is against the snapshot, so it must be provided")) {
|
||||
validateElement(errors, pr, pr.getSnapshot().getElement().get(0), null, null, element, element.getName(), stack, false);
|
||||
validateElement(errors, pr, pr.getSnapshot().getElement().get(0), null, null, element, element.getName(), stack);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
@ -594,7 +625,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.getAttribute("value")), "The value '" + e.getAttribute("value") + "' does not have a valid year");
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path,
|
||||
e.getAttribute("value")
|
||||
.matches("-?[0-9]{4}(-(0[1-9]|1[0-2])(-(0[0-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"),
|
||||
.matches("-?[0-9]{4}(-(0[1-9]|1[0-2])(-(0[0-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"),
|
||||
"Not a valid date time");
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, !hasTime(e.getAttribute("value")) || hasTimeZone(e.getAttribute("value")), "if a date has a time, it must have a timezone");
|
||||
|
||||
|
@ -619,29 +650,42 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
// note that we don't check the type here; it could be string, uri or code.
|
||||
private void checkPrimitiveBinding(List<ValidationMessage> errors, String path, String type, ElementDefinition elementContext, WrapperElement element) throws Exception {
|
||||
private void checkPrimitiveBinding(List<ValidationMessage> errors, String path, String type, ElementDefinition context, WrapperElement element) throws Exception {
|
||||
if (!element.hasAttribute("value"))
|
||||
return;
|
||||
|
||||
String value = element.getAttribute("value");
|
||||
String system = null;
|
||||
String display = null;
|
||||
|
||||
// System.out.println("check "+value+" in "+path);
|
||||
|
||||
// firstly, resolve the value set
|
||||
ElementDefinitionBindingComponent binding = elementContext.getBinding();
|
||||
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 {0} not found", describeReference(binding.getValueSet()))) {
|
||||
ValidationResult vr = context.validateCode(system, value, display, vs);
|
||||
if (!vr.isOk()) {
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + vs.getUrl() + ", and a code is required from this value set");
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + vs.getUrl() + ", and a code should come from this value set unless it has no suitable code");
|
||||
else if (binding.getStrength() == BindingStrength.PREFERRED)
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + vs.getUrl() + ", and a code is recommended to come from this value set");
|
||||
}
|
||||
try {
|
||||
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 {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 {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 {0} is not in value set {1} ({2})", value, describeReference(binding.getValueSet()),
|
||||
vs.getUrl());
|
||||
}
|
||||
} catch (ETooCostly e) {
|
||||
if (e.getMessage() == null)
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false,
|
||||
"Exception opening value set " + vs.getUrl() + " for " + describeReference(binding.getValueSet()) + ": --Null--");
|
||||
else
|
||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false,
|
||||
"Exception opening value set " + vs.getUrl() + " for " + describeReference(binding.getValueSet()) + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} else
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding has no source, so can't be checked");
|
||||
|
@ -746,7 +790,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return true;
|
||||
if (codeinExpansion(c, system, code))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -810,11 +854,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return base + id;
|
||||
else
|
||||
return Utilities.appendSlash(base) + type + "/" + id;
|
||||
}
|
||||
}
|
||||
|
||||
public BestPracticeWarningLevel getBasePracticeWarningLevel() {
|
||||
return bpWarnings;
|
||||
}
|
||||
}
|
||||
|
||||
private String getBaseType(StructureDefinition profile, String pr) throws EOperationOutcome, Exception {
|
||||
// if (pr.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
|
@ -836,17 +880,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return checkDisplay;
|
||||
}
|
||||
|
||||
// private String findProfileTag(WrapperElement element) {
|
||||
// String uri = null;
|
||||
// List<WrapperElement> list = new ArrayList<WrapperElement>();
|
||||
// element.getNamedChildren("category", list);
|
||||
// for (WrapperElement c : list) {
|
||||
// if ("http://hl7.org/fhir/tag/profile".equals(c.getAttribute("scheme"))) {
|
||||
// uri = c.getAttribute("term");
|
||||
// }
|
||||
// }
|
||||
// return uri;
|
||||
// }
|
||||
// private String findProfileTag(WrapperElement element) {
|
||||
// String uri = null;
|
||||
// List<WrapperElement> list = new ArrayList<WrapperElement>();
|
||||
// element.getNamedChildren("category", list);
|
||||
// for (WrapperElement c : list) {
|
||||
// if ("http://hl7.org/fhir/tag/profile".equals(c.getAttribute("scheme"))) {
|
||||
// uri = c.getAttribute("term");
|
||||
// }
|
||||
// }
|
||||
// return uri;
|
||||
// }
|
||||
|
||||
private ConceptDefinitionComponent getCodeDefinition(ConceptDefinitionComponent c, String code) {
|
||||
if (code.equals(c.getCode()))
|
||||
|
@ -875,7 +919,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
WrapperElement res = we.isXml() ? we.getFirstChild() : we;
|
||||
if (id.equals(res.getNamedChildValue("id")))
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -883,7 +927,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return context;
|
||||
}
|
||||
|
||||
private ElementDefinition getCriteriaForDiscriminator(String path, ElementDefinition ed, String discriminator, StructureDefinition profile) throws Exception {
|
||||
private ElementDefinition getCriteriaForDiscriminator(String path, ElementDefinition ed, String discriminator, StructureDefinition profile, List<ValidationMessage> errors) throws Exception {
|
||||
List<ElementDefinition> childDefinitions = ProfileUtilities.getChildMap(profile, ed);
|
||||
List<ElementDefinition> snapshot = null;
|
||||
if (childDefinitions.isEmpty()) {
|
||||
|
@ -892,14 +936,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
throw new Exception("Error in profile for " + path + " no children, no type");
|
||||
if (ed.getType().size() > 1)
|
||||
throw new Exception("Error in profile for " + path + " multiple types defined in slice discriminator");
|
||||
StructureDefinition type;
|
||||
|
||||
String url;
|
||||
if (ed.getType().get(0).hasProfile()) {
|
||||
// need to do some special processing for reference here...
|
||||
if (ed.getType().get(0).getCode().equals("Reference"))
|
||||
discriminator = discriminator.substring(discriminator.indexOf(".")+1);
|
||||
type = context.fetchResource(StructureDefinition.class, ed.getType().get(0).getProfile().get(0).getValue());
|
||||
} else
|
||||
type = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + ed.getType().get(0).getCode());
|
||||
url = ed.getType().get(0).getProfile().get(0).getValue();
|
||||
} else {
|
||||
url = "http://hl7.org/fhir/StructureDefinition/" + ed.getType().get(0).getCode();
|
||||
}
|
||||
StructureDefinition type = context.fetchResource(StructureDefinition.class, url);
|
||||
if (type == null) {
|
||||
super.fail(errors, IssueType.INCOMPLETE, path, false, "Failed to retrieve StructureDefinition with URL: " + url);
|
||||
return null;
|
||||
}
|
||||
snapshot = type.getSnapshot().getElement();
|
||||
ed = snapshot.get(0);
|
||||
} else {
|
||||
|
@ -943,15 +991,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private StructureDefinition getProfileForType(String type) throws Exception {
|
||||
return context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + type);
|
||||
}
|
||||
|
||||
private Element getValueForDiscriminator(WrapperElement element, String discriminator, ElementDefinition criteria) {
|
||||
// throw new Error("validation of slices not done yet");
|
||||
return null;
|
||||
throw new Error("validation of slices not done yet");
|
||||
}
|
||||
|
||||
private ValueSet getValueSet(String system) throws Exception {
|
||||
|
@ -968,17 +1015,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
private boolean isAbsolute(String uri) {
|
||||
return Utilities.noString(uri) || uri.startsWith("http:") || uri.startsWith("https:") || uri.startsWith("urn:uuid:") || uri.startsWith("urn:oid:") || uri.startsWith("urn:ietf:")
|
||||
|| uri.startsWith("urn:iso:") || isValidFHIRUrn(uri);
|
||||
}
|
||||
|
||||
private boolean isValidFHIRUrn(String uri) {
|
||||
return (uri.equals("urn:x-fhir:uk:id:nhs-number"));
|
||||
|| uri.startsWith("urn:iso:");
|
||||
}
|
||||
|
||||
public boolean isAnyExtensionsAllowed() {
|
||||
return anyExtensionsAllowed;
|
||||
}
|
||||
|
||||
private boolean isBundleEntry(String path) {
|
||||
String[] parts = path.split("\\/");
|
||||
if (path.startsWith("/f:"))
|
||||
return parts.length > 2 && parts[parts.length - 1].startsWith("f:resource") && (parts[parts.length - 2].equals("f:entry") || parts[parts.length - 2].startsWith("f:entry["));
|
||||
else
|
||||
return parts.length > 2 && parts[parts.length - 1].equals("resource") && ((parts.length > 2 && parts[parts.length - 3].equals("entry")) || parts[parts.length - 2].equals("entry"));
|
||||
}
|
||||
|
||||
private boolean isParametersEntry(String path) {
|
||||
String[] parts = path.split("\\/");
|
||||
if (path.startsWith("/f:"))
|
||||
|
@ -987,14 +1038,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return parts.length == 4 && parts[parts.length-3].equals("Parameters") && parts[parts.length-2].startsWith("parameter") && parts[parts.length-1].startsWith("resource");
|
||||
}
|
||||
|
||||
private boolean isBundleEntry(String path) {
|
||||
String[] parts = path.split("\\/");
|
||||
if (path.startsWith("/f:"))
|
||||
return parts.length > 2 && parts[parts.length - 1].startsWith("f:resource") && (parts[parts.length - 2].equals("f:entry") || parts[parts.length - 2].startsWith("f:entry["));
|
||||
else
|
||||
return parts.length > 2 && parts[parts.length - 1].equals("resource") && ((parts.length > 2 && parts[parts.length - 3].equals("entry")) || parts[parts.length - 2].equals("entry"));
|
||||
}
|
||||
|
||||
private boolean isPrimitiveType(String type) {
|
||||
return type.equalsIgnoreCase("boolean") || type.equalsIgnoreCase("integer") || type.equalsIgnoreCase("string") || type.equalsIgnoreCase("decimal") || type.equalsIgnoreCase("uri")
|
||||
|| type.equalsIgnoreCase("base64Binary") || type.equalsIgnoreCase("instant") || type.equalsIgnoreCase("date") || type.equalsIgnoreCase("uuid") || type.equalsIgnoreCase("id")
|
||||
|
@ -1086,7 +1129,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
private WrapperElement resolveInBundle(List<WrapperElement> entries, String ref, String fullUrl, String type, String id) {
|
||||
if (Utilities.isAbsoluteUrl(ref)) {
|
||||
// if the reference is absolute, then you resolve by fullUrl. No other thinking is required.
|
||||
// if the reference is absolute, then you resolve by fullUrl. No other thinking is required.
|
||||
for (WrapperElement entry : entries) {
|
||||
String fu = entry.getNamedChildValue("fullUrl");
|
||||
if (ref.equals(fu))
|
||||
|
@ -1096,9 +1139,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else {
|
||||
// split into base, type, and id
|
||||
String u = null;
|
||||
if (fullUrl != null && fullUrl.endsWith(type+"/"+id))
|
||||
if (fullUrl != null && fullUrl.endsWith(type + "/" + id))
|
||||
// fullUrl = complex
|
||||
u = fullUrl.substring((type+"/"+id).length())+ref;
|
||||
u = fullUrl.substring((type + "/" + id).length()) + ref;
|
||||
String[] parts = ref.split("\\/");
|
||||
if (parts.length >= 2) {
|
||||
String t = parts[0];
|
||||
|
@ -1179,15 +1222,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
* - the definition of how slicing is determined
|
||||
* @param ed
|
||||
* - the slice for which to test membership
|
||||
* @param errors
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private boolean sliceMatches(WrapperElement element, String path, ElementDefinition slice, ElementDefinition ed, StructureDefinition profile) throws Exception {
|
||||
private boolean sliceMatches(WrapperElement element, String path, ElementDefinition slice, ElementDefinition ed, StructureDefinition profile, List<ValidationMessage> errors) throws Exception {
|
||||
if (!slice.getSlicing().hasDiscriminator())
|
||||
return false; // cannot validate in this case
|
||||
for (StringType s : slice.getSlicing().getDiscriminator()) {
|
||||
String discriminator = s.getValue();
|
||||
ElementDefinition criteria = getCriteriaForDiscriminator(path, ed, discriminator, profile);
|
||||
ElementDefinition criteria = getCriteriaForDiscriminator(path, ed, discriminator, profile, errors);
|
||||
if (criteria == null) {
|
||||
return false;
|
||||
}
|
||||
if (discriminator.equals("url") && criteria.getPath().equals("Extension.url")) {
|
||||
if (!element.getAttribute("url").equals(((UriType) criteria.getFixed()).asStringValue()))
|
||||
return false;
|
||||
|
@ -1207,7 +1254,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// profile is valid, and matches the resource name
|
||||
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), profile.hasSnapshot(),
|
||||
"StructureDefinition has no snapshot - validation is against the snapshot, so it must be provided")) {
|
||||
validateElement(errors, profile, profile.getSnapshot().getElement().get(0), null, null, element, element.getName(), stack, false);
|
||||
validateElement(errors, profile, profile.getSnapshot().getElement().get(0), null, null, element, element.getName(), stack);
|
||||
|
||||
checkDeclaredProfiles(errors, element, stack);
|
||||
|
||||
|
@ -1266,7 +1313,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
List<ValidationMessage> results = new ArrayList<ValidationMessage>();
|
||||
validate(results, document, profile);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ValidationMessage> validate(Element element) throws Exception {
|
||||
|
@ -1314,7 +1361,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
public void validate(List<ValidationMessage> errors, Document document) throws Exception {
|
||||
checkForProcessingInstruction(errors, document);
|
||||
validateResource(errors, new DOMWrapperElement(document.getDocumentElement()), null, requiresResourceId, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(List<ValidationMessage> errors, Document document, String profile) throws Exception {
|
||||
|
@ -1638,7 +1685,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// firstBase = ebase == null ? base : ebase;
|
||||
|
||||
private void validateElement(List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, StructureDefinition cprofile, ElementDefinition context,
|
||||
WrapperElement element, String actualType, NodeStack stack, boolean inCodeableConcept) throws Exception {
|
||||
WrapperElement element, String actualType, NodeStack stack) throws Exception {
|
||||
// irrespective of what element it is, it cannot be empty
|
||||
if (element.isXml()) {
|
||||
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), FormatUtilities.FHIR_NS.equals(element.getNamespace()),
|
||||
|
@ -1679,7 +1726,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
match = nameMatches(ei.name, tail(ed.getPath()));
|
||||
} else {
|
||||
if (nameMatches(ei.name, tail(ed.getPath())))
|
||||
match = sliceMatches(ei.element, ei.path, slice, ed, profile);
|
||||
match = sliceMatches(ei.element, ei.path, slice, ed, profile, errors);
|
||||
}
|
||||
if (match) {
|
||||
if (rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, ei.definition == null, "Element matches more than one slice"))
|
||||
|
@ -1742,7 +1789,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
TypeRefComponent trc = ei.definition.getType().get(0);
|
||||
if (trc.getCode().equals("Reference"))
|
||||
type = "Reference";
|
||||
else
|
||||
else
|
||||
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), false,
|
||||
"The element " + ei.name + " is illegal. Valid types at this point are " + describeTypes(ei.definition.getType()));
|
||||
}
|
||||
|
@ -1760,7 +1807,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
String localStackLiterapPath = localStack.getLiteralPath();
|
||||
String eiPath = ei.path;
|
||||
assert(eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.path + " - localStack.getLiterapPath: " + localStackLiterapPath;
|
||||
boolean thisIsCodeableConcept = false;
|
||||
|
||||
if (type != null) {
|
||||
if (isPrimitiveType(type))
|
||||
|
@ -1769,28 +1815,27 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (type.equals("Identifier"))
|
||||
checkIdentifier(errors, ei.path, ei.element, ei.definition);
|
||||
else if (type.equals("Coding"))
|
||||
checkCoding(errors, ei.path, ei.element, profile, ei.definition, inCodeableConcept);
|
||||
else if (type.equals("CodeableConcept")) {
|
||||
checkCoding(errors, ei.path, ei.element, profile, ei.definition);
|
||||
else if (type.equals("CodeableConcept"))
|
||||
checkCodeableConcept(errors, ei.path, ei.element, profile, ei.definition);
|
||||
thisIsCodeableConcept = true;
|
||||
} else if (type.equals("Reference"))
|
||||
else if (type.equals("Reference"))
|
||||
checkReference(errors, ei.path, ei.element, profile, ei.definition, actualType, localStack);
|
||||
|
||||
|
||||
if (type.equals("Extension"))
|
||||
checkExtension(errors, ei.path, ei.element, ei.definition, profile, localStack);
|
||||
else if (type.equals("Resource"))
|
||||
validateContains(errors, ei.path, ei.definition, definition, ei.element, localStack, !isBundleEntry(ei.path) && !isParametersEntry(ei.path)); // if
|
||||
// (str.matches(".*([.,/])work\\1$"))
|
||||
validateContains(errors, ei.path, ei.definition, definition, ei.element, localStack, !isBundleEntry(ei.path) && !isParametersEntry(ei.path)); // if
|
||||
// (str.matches(".*([.,/])work\\1$"))
|
||||
else {
|
||||
StructureDefinition p = getProfileForType(type);
|
||||
if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, p != null, "Unknown type " + type)) {
|
||||
validateElement(errors, p, p.getSnapshot().getElement().get(0), profile, ei.definition, ei.element, type, localStack, thisIsCodeableConcept);
|
||||
validateElement(errors, p, p.getSnapshot().getElement().get(0), profile, ei.definition, ei.element, type, localStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), ei.definition != null, "Unrecognised Content " + ei.name))
|
||||
validateElement(errors, profile, ei.definition, null, null, ei.element, type, localStack, false);
|
||||
validateElement(errors, profile, ei.definition, null, null, ei.element, type, localStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1830,15 +1875,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
ok = rule(errors, IssueType.INVALID, element.line(), element.col(), stack.addToLiteralPath(resourceName), profile != null, "No profile found for resource type '" + resourceName + "'");
|
||||
} else {
|
||||
String type = profile.hasConstrainedType() ? profile.getConstrainedType() : profile.getName();
|
||||
// special case: we have a bundle, and the profile is not for a bundle. We'll try the first entry instead
|
||||
if (!type.equals(resourceName) && resourceName.equals("Bundle")) {
|
||||
WrapperElement first = getFirstEntry(element);
|
||||
if (first != null && first.getResourceType().equals(type)) {
|
||||
element = first;
|
||||
resourceName = element.getResourceType();
|
||||
needsId = false;
|
||||
}
|
||||
}
|
||||
ok = rule(errors, IssueType.INVALID, -1, -1, stack.addToLiteralPath(resourceName), type.equals(resourceName),
|
||||
"Specified profile type was '" + profile.getConstrainedType() + "', but resource type was '" + resourceName + "'");
|
||||
}
|
||||
|
@ -1852,18 +1888,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
|
||||
private WrapperElement getFirstEntry(WrapperElement bundle) {
|
||||
List<WrapperElement> list = new ArrayList<WrapperElement>();
|
||||
bundle.getNamedChildren("entry", list);
|
||||
if (list.isEmpty())
|
||||
return null;
|
||||
WrapperElement resource = list.get(0).getNamedChild("resource");
|
||||
if (resource == null)
|
||||
return null;
|
||||
else
|
||||
return resource.getFirstChild();
|
||||
}
|
||||
|
||||
private void validateSections(List<ValidationMessage> errors, List<WrapperElement> entries, WrapperElement focus, NodeStack stack, String fullUrl, String id) {
|
||||
List<WrapperElement> sections = new ArrayList<WrapperElement>();
|
||||
focus.getNamedChildren("entry", sections);
|
||||
|
@ -1877,8 +1901,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
private boolean valueMatchesCriteria(Element value, ElementDefinition criteria) {
|
||||
// throw new Error("validation of slices not done yet");
|
||||
return false;
|
||||
throw new Error("validation of slices not done yet");
|
||||
}
|
||||
|
||||
private boolean yearIsValid(String v) {
|
||||
|
@ -2079,6 +2102,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
public int line() {
|
||||
return line;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ElementInfo {
|
||||
|
@ -2148,25 +2172,23 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private void createChildren() {
|
||||
// System.out.println(" ..: "+path);
|
||||
// we're going to make this look like the XML
|
||||
if (element != null) {
|
||||
if (element instanceof JsonPrimitive) {
|
||||
// we may have an element_ too
|
||||
if (_element != null && _element instanceof JsonObject)
|
||||
for (Entry<String, JsonElement> t : ((JsonObject) _element).entrySet())
|
||||
processChild(t.getKey(), t.getValue());
|
||||
} else if (element instanceof JsonObject) {
|
||||
for (Entry<String, JsonElement> t : ((JsonObject) element).entrySet())
|
||||
if (!t.getKey().equals("resourceType")) {
|
||||
processChild(t.getKey(), t.getValue());
|
||||
}
|
||||
} else if (element instanceof JsonNull) {
|
||||
// nothing to do
|
||||
} else
|
||||
throw new Error("unexpected condition: " + element.getClass().getName());
|
||||
}
|
||||
if (_element != null) {
|
||||
if (element == null)
|
||||
throw new Error("not done yet");
|
||||
|
||||
}
|
||||
if (element instanceof JsonPrimitive) {
|
||||
// we may have an element_ too
|
||||
if (_element != null && _element instanceof JsonObject)
|
||||
for (Entry<String, JsonElement> t : ((JsonObject) _element).entrySet())
|
||||
processChild(t.getKey(), t.getValue());
|
||||
} else if (element instanceof JsonObject) {
|
||||
for (Entry<String, JsonElement> t : ((JsonObject) element).entrySet())
|
||||
if (!t.getKey().equals("resourceType")) {
|
||||
processChild(t.getKey(), t.getValue());
|
||||
}
|
||||
} else if (element instanceof JsonNull) {
|
||||
// nothing to do
|
||||
} else
|
||||
throw new Error("unexpected condition: " + element.getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2281,7 +2303,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
@Override
|
||||
public boolean isXml() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int line() {
|
||||
|
@ -2330,7 +2352,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
public NodeStack(boolean xml) {
|
||||
this.xml = xml;
|
||||
}
|
||||
}
|
||||
|
||||
public String addToLiteralPath(String... path) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
@ -2344,8 +2366,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else {
|
||||
b.append("/f:");
|
||||
b.append(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String p : path) {
|
||||
b.append("/");
|
||||
|
@ -2353,9 +2375,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
b.append(p.substring(1));
|
||||
} else {
|
||||
b.append(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,14 @@ import static org.mockito.Matchers.any;
|
|||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
||||
|
@ -24,11 +26,13 @@ import org.hl7.fhir.instance.model.Observation;
|
|||
import org.hl7.fhir.instance.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.instance.model.Patient;
|
||||
import org.hl7.fhir.instance.model.StringType;
|
||||
import org.hl7.fhir.instance.model.StructureDefinition;
|
||||
import org.hl7.fhir.instance.model.ValueSet;
|
||||
import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.validation.InstanceValidator;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
@ -45,7 +49,27 @@ public class FhirInstanceValidatorTest {
|
|||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2Hl7Org();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorTest.class);
|
||||
private static DefaultProfileValidationSupport ourDefaultValidationSupport = new DefaultProfileValidationSupport();
|
||||
private static DefaultProfileValidationSupport ourDefaultValidationSupport = new DefaultProfileValidationSupport() {
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
if (theUri.equals("http://fhir.hl7.org.nz/dstu2/StructureDefinition/ohAllergyIntolerance")) {
|
||||
String contents;
|
||||
try {
|
||||
contents = IOUtils.toString(getClass().getResourceAsStream("/allergyintolerance-sd-david.json"), "UTF-8");
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
StructureDefinition sd = ourCtx.newJsonParser().parseResource(StructureDefinition.class, contents);
|
||||
return (T) sd;
|
||||
}
|
||||
T retVal = super.fetchResource(theContext, theClass, theUri);
|
||||
if (retVal == null) {
|
||||
ourLog.warn("Can not fetch: {}", theUri);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
};
|
||||
private FhirInstanceValidator myInstanceVal;
|
||||
private IValidationSupport myMockSupport;
|
||||
|
||||
|
@ -102,9 +126,10 @@ public class FhirInstanceValidatorTest {
|
|||
.thenAnswer(new Answer<IBaseResource>() {
|
||||
@Override
|
||||
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource retVal = ourDefaultValidationSupport.fetchResource(
|
||||
(FhirContext) theInvocation.getArguments()[0], (Class<IBaseResource>) theInvocation.getArguments()[1],
|
||||
(String) theInvocation.getArguments()[2]);
|
||||
FhirContext fhirContext = (FhirContext) theInvocation.getArguments()[0];
|
||||
Class<IBaseResource> type = (Class<IBaseResource>) theInvocation.getArguments()[1];
|
||||
String uri = (String) theInvocation.getArguments()[2];
|
||||
IBaseResource retVal = ourDefaultValidationSupport.fetchResource(fhirContext, type, uri);
|
||||
ourLog.info("fetchResource({}, {}) : {}",
|
||||
new Object[] { theInvocation.getArguments()[1], theInvocation.getArguments()[2], retVal });
|
||||
return retVal;
|
||||
|
@ -188,6 +213,20 @@ public class FhirInstanceValidatorTest {
|
|||
assertEquals(output.toString(), 0, output.getMessages().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Received by email from David Hay
|
||||
*/
|
||||
@Test
|
||||
public void testValidateAllergyIntoleranceFromDavid() throws Exception {
|
||||
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/allergyintolerance-david.json"), "UTF-8");
|
||||
|
||||
// Just make sure this doesn't crash
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
ourLog.info(output.toString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateRawJsonResourceBadAttributes() {
|
||||
// @formatter:off
|
||||
|
@ -327,7 +366,7 @@ public class FhirInstanceValidatorTest {
|
|||
+ " <code>\n" + " <text value=\"No code here!\"/>\n" + " </code>\n" + "</Observation>";
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
assertEquals(
|
||||
"The value provided is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status, and a code is required from this value set",
|
||||
"Coded value notvalidcode is not in value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status)",
|
||||
output.getMessages().get(0).getMessage());
|
||||
}
|
||||
|
||||
|
@ -342,16 +381,16 @@ public class FhirInstanceValidatorTest {
|
|||
|
||||
ValidationResult output = myVal.validateWithResult(patient);
|
||||
List<SingleValidationMessage> all = logResultsAndReturnAll(output);
|
||||
assertEquals(1, all.size());
|
||||
assertEquals(2, all.size());
|
||||
assertEquals("/f:Patient/f:identifier/f:type", all.get(0).getLocationString());
|
||||
assertEquals("None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type, and a code should come from this value set unless it has no suitable code", all.get(0).getMessage());
|
||||
assertEquals("None of the codes are in the expected value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type)", all.get(0).getMessage());
|
||||
assertEquals(ResultSeverityEnum.WARNING, all.get(0).getSeverity());
|
||||
|
||||
patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://system").setValue("12345").getType().addCoding().setSystem("http://hl7.org/fhir/v2/0203").setCode("MR");
|
||||
|
||||
output = myVal.validateWithResult(patient);
|
||||
all = logResultsAndReturnAll(output);
|
||||
all = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertEquals(0, all.size());
|
||||
}
|
||||
|
||||
|
@ -367,8 +406,8 @@ public class FhirInstanceValidatorTest {
|
|||
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertEquals(errors.toString(), 0, errors.size());
|
||||
|
||||
assertEquals(errors.toString(), 1, errors.size());
|
||||
assertEquals("Unable to validate code \"12345\" in code system \"http://loinc.org\"", errors.get(0).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -402,8 +441,8 @@ public class FhirInstanceValidatorTest {
|
|||
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertEquals(errors.toString(), 0, errors.size());
|
||||
|
||||
assertEquals(errors.toString(), 1, errors.size());
|
||||
assertEquals("Unable to validate code \"1234\" in code system \"http://loinc.org\"", errors.get(0).getMessage());
|
||||
|
||||
}
|
||||
|
||||
|
@ -418,7 +457,7 @@ public class FhirInstanceValidatorTest {
|
|||
input.getCode().addCoding().setSystem("http://acme.org").setCode("12345");
|
||||
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertEquals(errors.toString(), 0, errors.size());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"resourceType": "AllergyIntolerance",
|
||||
"id": "84651",
|
||||
"meta": {
|
||||
"versionId": "1",
|
||||
"lastUpdated": "2016-05-19T15:43:49.815-04:00",
|
||||
"profile": [
|
||||
"http://fhir.hl7.org.nz/dstu2/StructureDefinition/ohAllergyIntolerance"
|
||||
]
|
||||
},
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-endDate",
|
||||
"valueDateTime": "2016-05-03"
|
||||
},
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-informantRole",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "133932002",
|
||||
"display": "Carer"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-reasonClosed",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/adverse-reaction-reason-closed",
|
||||
"code": "1",
|
||||
"display": "Disproven"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-classification",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "419076005",
|
||||
"display": "Allergic reaction"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"language": [
|
||||
"en"
|
||||
],
|
||||
"identifier": [
|
||||
{
|
||||
"system": "http://orionhealth.com/identifier/problem-list/ORGNISATION_ORION",
|
||||
"value": "2.25.148135789146703435349240718177383549558.8.4.4.0/522911"
|
||||
}
|
||||
],
|
||||
"patient": {
|
||||
"reference": "Patient/64909"
|
||||
},
|
||||
"substance": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "84430008",
|
||||
"display": "Cross reacting antibody"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": "inactive",
|
||||
"criticality": "CRITH",
|
||||
"category": "environment",
|
||||
"reaction": [
|
||||
{
|
||||
"certainty": "likely",
|
||||
"_certainty": {
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/originalValue",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/adverse-reaction-certainty",
|
||||
"code": "SUSPECTED",
|
||||
"display": "Suspected"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"manifestation": [
|
||||
{
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-manifestationSeverity",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/900000000000207008/version/20150531",
|
||||
"code": "442452003",
|
||||
"display": "Life-Threatening"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/clinical-manifestation",
|
||||
"code": "FT",
|
||||
"display": "rlo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://fhir.hl7.org.nz/dstu2/StructureDefinition/al-manifestationSeverity",
|
||||
"valueCodeableConcept": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://orionhealth.com/problem-list/severity",
|
||||
"code": "UNKNOWN",
|
||||
"display": "Unknown"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"version": "http://snomed.info/sct/32506021000036107/version/20150531",
|
||||
"code": "95332009",
|
||||
"display": "Rash of systemic lupus erythematosus"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"severity": "severe"
|
||||
}
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -234,6 +234,9 @@
|
|||
had any extensions. Thanks to GitHub user @Virdulys for submitting and
|
||||
providing a test case!
|
||||
</action>
|
||||
<action type="add">
|
||||
Update DSTU2 InstanceValidator to latest version from upstream
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.5" date="2016-04-20">
|
||||
<action type="fix" issue="339">
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
hapifhir.io
|
Loading…
Reference in New Issue