diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
index 1447b7469..c218f4c6b 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
@@ -1098,6 +1098,10 @@ public abstract class BaseWorkerContext implements IWorkerContext {
@Override
public String oid2Uri(String oid) {
synchronized (lock) {
+ if (oid != null && oid.startsWith("urn:oid:")) {
+ oid = oid.substring(8);
+ }
+
String uri = OIDUtils.getUriForOid(oid);
if (uri != null)
return uri;
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java
index dc1c242b8..e7e03c860 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java
@@ -248,6 +248,7 @@ public interface IWorkerContext {
* @throws FHIRException
*/
public void generateSnapshot(StructureDefinition p) throws DefinitionException, FHIRException;
+ public void generateSnapshot(StructureDefinition mr, boolean ifLogical);
// -- Terminology services ------------------------------------------------------
@@ -543,4 +544,5 @@ public interface IWorkerContext {
public String getLinkForUrl(String corePath, String s);
+
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java
index 725a08b74..7f0657ee1 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java
@@ -593,10 +593,12 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
return r;
}
+ @Override
public void generateSnapshot(StructureDefinition p) throws DefinitionException, FHIRException {
generateSnapshot(p, false);
}
+ @Override
public void generateSnapshot(StructureDefinition p, boolean logical) throws DefinitionException, FHIRException {
if (!p.hasSnapshot() && (logical || p.getKind() != StructureDefinitionKind.LOGICAL)) {
if (!p.hasBaseDefinition())
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java
index 02d9fee88..b1734497e 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java
@@ -176,7 +176,7 @@ public class Property {
if (definition.getType().size() > 0)
return definition.getType().size() == 1 && ("Resource".equals(definition.getType().get(0).getCode()) || "DomainResource".equals(definition.getType().get(0).getCode()));
else
- return !definition.getPath().contains(".") && structure.getKind() == StructureDefinitionKind.RESOURCE;
+ return !definition.getPath().contains(".") && (structure.getKind() == StructureDefinitionKind.RESOURCE || structure.getKind() == StructureDefinitionKind.LOGICAL);
}
public boolean isList() {
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java
index c7e1bdb26..f0dd0996d 100644
--- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java
@@ -17,6 +17,8 @@ import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
+import org.hl7.fhir.r5.model.StructureDefinition;
+import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionDifferentialComponent;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.utilities.cache.PackageCacheManager;
@@ -25,158 +27,184 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import junit.framework.Assert;
+
public class CDARoundTripTests {
- private SimpleWorkerContext context;
- private FHIRPathEngine fp;
+// private SimpleWorkerContext context;
+// old-test private FHIRPathEngine fp;
@Before
public void setUp() throws Exception {
- context = new SimpleWorkerContext();
- PackageCacheManager pcm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
- context.loadFromPackage(pcm.loadPackage("hl7.fhir.core", "dev"), null, "StructureDefinition");
- context.loadFromPackage(pcm.loadPackage("hl7.fhir.cda", "dev"), null, "StructureDefinition");
- fp = new FHIRPathEngine(context);
+// old-test context = new SimpleWorkerContext();
+// old-test PackageCacheManager pcm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
+// old-test context.loadFromPackage(pcm.loadPackage("hl7.fhir.core", "dev"), null, "StructureDefinition");
+// old-test context.loadFromPackage(pcm.loadPackage("hl7.fhir.cda", "dev"), null, "StructureDefinition");
+// old-test fp = new FHIRPathEngine(context);
}
+// old-test
+// @Test
+// public void testCDA() throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
+// try {
+//
+// InputStream fileSource = TestingUtilities.loadTestResourceStream("cda", "cda-original.xml");
+// String roundTrip = TestingUtilities.tempFile("cda", "cda-roundtrip.xml");
+// String jsonRoundTrip = TestingUtilities.tempFile("cda", "cda-roundtrip.json");
+//
+// Element e = Manager.parse(context, fileSource, FhirFormat.XML);
+//
+// Manager.compose(context, e, new FileOutputStream(roundTrip), FhirFormat.XML, OutputStyle.PRETTY, null);
+// Manager.compose(context, e, new FileOutputStream(jsonRoundTrip), FhirFormat.JSON, OutputStyle.PRETTY, null);
+//
+////
+//// assertEquals("POCD_HD000040", fp.evaluateToString(e, "typeId.extension"));
+//// assertEquals("2.16.840.1.113883.1.3", fp.evaluateToString(e, "typeId.root"));
+////
+//// assertEquals("2.16.840.1.113883.3.27.1776", fp.evaluateToString(e, "templateId.root"));
+////
+// assertEquals("2.16.840.1.113883.19.4", fp.evaluateToString(e, "id.root"));
+// assertEquals("c266", fp.evaluateToString(e, "id.extension"));
+//
+////
Good Health Clinic Consultation Note
+// assertEquals("Good Health Clinic Consultation Note", fp.evaluateToString(e, "title.dataString"));
+////
+// assertEquals("2000-04-07", fp.evaluateToString(e, "effectiveTime.value"));
+////
+// assertEquals("N", fp.evaluateToString(e, "confidentialityCode.code"));
+// assertEquals("2.16.840.1.113883.5.25", fp.evaluateToString(e, "confidentialityCode.codeSystem"));
+////
+// assertEquals("en-US", fp.evaluateToString(e, "languageCode.code"));
+////
+// assertEquals("BB35", fp.evaluateToString(e, "setId.extension"));
+// assertEquals("2.16.840.1.113883.19.7", fp.evaluateToString(e, "setId.root"));
+////
+// assertEquals("2", fp.evaluateToString(e, "versionNumber.value"));
+////
+////
+////
+// assertEquals("12345", fp.evaluateToString(e, "recordTarget.patientRole.id.extension"));
+// assertEquals("2.16.840.1.113883.19.5", fp.evaluateToString(e, "recordTarget.patientRole.id.root"));
+////
+////
+//// Levin
+// assertEquals("Levin", fp.evaluateToString(e, "recordTarget.patientRole.patient.name.family.dataString"));
+//// Henry
+// assertEquals("Henry", fp.evaluateToString(e, "recordTarget.patientRole.patient.name.given.dataString"));
+//// the 7th
+////
+////
+////
+////
+////
+////
+////
+////
+////
+//
+////
+////
+////
+////
+//
+////
+////
+////
+//// Skin Exam
+//// Erythematous rash, palmar surface, left index finger.
+////
+////
+//
+// assertEquals("Skin Exam", fp.evaluateToString(e, "component.structuredBody.component.section.component.section.where(code.code='8709-8' and code.codeSystem='2.16.840.1.113883.6.1').title.dataString"));
+// // Erythematous rash, palmar surface, left index finger.
+// //
+// String text = fp.evaluateToString(e, "component.structuredBody.component.section.component.section.where(code.code='8709-8' and code.codeSystem='2.16.840.1.113883.6.1').text");
+// assertTrue(text.contains(""));
+// } catch (Exception e) {
+// System.out.println(e.getMessage());
+// e.printStackTrace();
+// throw e;
+// }
+// }
+//
+// @Ignore
+// public void testDCI() throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
+// try {
+// Element e = Manager.parse(context,
+// new FileInputStream("C:\\work\\org.hl7.fhir.us\\ccda-to-fhir-maps\\cda\\IAT2-Discharge_Summary-DCI.xml"),
+// FhirFormat.XML);
+//
+// Manager.compose(context, e, new FileOutputStream("C:\\temp\\ccda.xml"), FhirFormat.XML, OutputStyle.PRETTY, null);
+//// Manager.compose(context, e, new FileOutputStream("C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge_Summary-DCI.out.json"), FhirFormat.JSON, OutputStyle.PRETTY, null);
+//// Manager.compose(context, e, new FileOutputStream("C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge_Summary-DCI.out.ttl"), FhirFormat.TURTLE, OutputStyle.PRETTY, null);
+// } catch (Exception e) {
+// System.out.println(e.getMessage());
+// e.printStackTrace();
+// throw e;
+// }
+// }
+//
+// @Ignore
+// public void testEpic()
+// throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
+// Element e = Manager.parse(context,
+// new FileInputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.xml"),
+// FhirFormat.XML);
+// Manager.compose(context, e,
+// new FileOutputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.out.xml"),
+// FhirFormat.XML, OutputStyle.PRETTY, null);
+// Manager.compose(context, e,
+// new FileOutputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.out.json"),
+// FhirFormat.JSON, OutputStyle.PRETTY, null);
+// Manager.compose(context, e,
+// new FileOutputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.out.ttl"),
+// FhirFormat.TURTLE, OutputStyle.PRETTY, null);
+// }
+//
+// @Ignore
+// public void testDHIT()
+// throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
+// Element e = Manager.parse(context,
+// new FileInputStream("C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.xml"),
+// FhirFormat.XML);
+// Manager.compose(context, e,
+// new FileOutputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.out.xml"),
+// FhirFormat.XML, OutputStyle.PRETTY, null);
+// Manager.compose(context, e,
+// new FileOutputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.out.json"),
+// FhirFormat.JSON, OutputStyle.PRETTY, null);
+// Manager.compose(context, e,
+// new FileOutputStream(
+// "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.out.ttl"),
+// FhirFormat.TURTLE, OutputStyle.PRETTY, null);
+// }
+
+
@Test
- public void testCDA() throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
- try {
-
- InputStream fileSource = TestingUtilities.loadTestResourceStream("cda", "cda-original.xml");
- String roundTrip = TestingUtilities.tempFile("cda", "cda-roundtrip.xml");
- String jsonRoundTrip = TestingUtilities.tempFile("cda", "cda-roundtrip.json");
-
- Element e = Manager.parse(context, fileSource, FhirFormat.XML);
-
- Manager.compose(context, e, new FileOutputStream(roundTrip), FhirFormat.XML, OutputStyle.PRETTY, null);
- Manager.compose(context, e, new FileOutputStream(jsonRoundTrip), FhirFormat.JSON, OutputStyle.PRETTY, null);
-
-//
-// assertEquals("POCD_HD000040", fp.evaluateToString(e, "typeId.extension"));
-// assertEquals("2.16.840.1.113883.1.3", fp.evaluateToString(e, "typeId.root"));
-//
-// assertEquals("2.16.840.1.113883.3.27.1776", fp.evaluateToString(e, "templateId.root"));
-//
- assertEquals("2.16.840.1.113883.19.4", fp.evaluateToString(e, "id.root"));
- assertEquals("c266", fp.evaluateToString(e, "id.extension"));
-
-// Good Health Clinic Consultation Note
- assertEquals("Good Health Clinic Consultation Note", fp.evaluateToString(e, "title.dataString"));
-//
- assertEquals("2000-04-07", fp.evaluateToString(e, "effectiveTime.value"));
-//
- assertEquals("N", fp.evaluateToString(e, "confidentialityCode.code"));
- assertEquals("2.16.840.1.113883.5.25", fp.evaluateToString(e, "confidentialityCode.codeSystem"));
-//
- assertEquals("en-US", fp.evaluateToString(e, "languageCode.code"));
-//
- assertEquals("BB35", fp.evaluateToString(e, "setId.extension"));
- assertEquals("2.16.840.1.113883.19.7", fp.evaluateToString(e, "setId.root"));
-//
- assertEquals("2", fp.evaluateToString(e, "versionNumber.value"));
-//
-//
-//
- assertEquals("12345", fp.evaluateToString(e, "recordTarget.patientRole.id.extension"));
- assertEquals("2.16.840.1.113883.19.5", fp.evaluateToString(e, "recordTarget.patientRole.id.root"));
-//
-//
-// Levin
- assertEquals("Levin", fp.evaluateToString(e, "recordTarget.patientRole.patient.name.family.dataString"));
-// Henry
- assertEquals("Henry", fp.evaluateToString(e, "recordTarget.patientRole.patient.name.given.dataString"));
-// the 7th
-//
-//
-//
-//
-//
-//
-//
-//
-//
-
-//
-//
-//
-//
-
-//
-//
-//
-// Skin Exam
-// Erythematous rash, palmar surface, left index finger.
-//
-//
-
- assertEquals("Skin Exam", fp.evaluateToString(e, "component.structuredBody.component.section.component.section.where(code.code='8709-8' and code.codeSystem='2.16.840.1.113883.6.1').title.dataString"));
- // Erythematous rash, palmar surface, left index finger.
- //
- String text = fp.evaluateToString(e, "component.structuredBody.component.section.component.section.where(code.code='8709-8' and code.codeSystem='2.16.840.1.113883.6.1').text");
- assertTrue(text.contains(""));
- } catch (Exception e) {
- System.out.println(e.getMessage());
- e.printStackTrace();
- throw e;
+ public void testSimple() throws IOException {
+ PackageCacheManager pcm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
+ SimpleWorkerContext context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1"));
+ context.loadFromFile(TestingUtilities.loadTestResourceStream("r5", "cda", "any.xml"), "any.xml", null);
+ context.loadFromFile(TestingUtilities.loadTestResourceStream("r5", "cda", "ii.xml"), "ii.xml", null);
+ context.loadFromFile(TestingUtilities.loadTestResourceStream("r5", "cda", "cd.xml"), "cd.xml", null);
+ context.loadFromFile(TestingUtilities.loadTestResourceStream("r5", "cda", "ce.xml"), "ce.xml", null);
+ context.loadFromFile(TestingUtilities.loadTestResourceStream("r5", "cda", "cda.xml"), "cda.xml", null);
+ for (StructureDefinition sd : context.getStructures()) {
+ if (!sd.hasSnapshot()) {
+ System.out.println("generate snapshot for "+sd.getUrl());
+ context.generateSnapshot(sd, true);
+ }
}
+ Element cda = Manager.parse(context, TestingUtilities.loadTestResourceStream("r5", "cda", "example.xml"), FhirFormat.XML);
+ FHIRPathEngine fp = new FHIRPathEngine(context);
+ Assert.assertEquals("2.16.840.1.113883.3.27.1776", fp.evaluateToString(null, cda, cda, cda, fp.parse("ClinicalDocument.templateId.root")));
+
}
-
- @Ignore
- public void testDCI() throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
- try {
- Element e = Manager.parse(context,
- new FileInputStream("C:\\work\\org.hl7.fhir.us\\ccda-to-fhir-maps\\cda\\IAT2-Discharge_Summary-DCI.xml"),
- FhirFormat.XML);
-
- Manager.compose(context, e, new FileOutputStream("C:\\temp\\ccda.xml"), FhirFormat.XML, OutputStyle.PRETTY, null);
-// Manager.compose(context, e, new FileOutputStream("C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge_Summary-DCI.out.json"), FhirFormat.JSON, OutputStyle.PRETTY, null);
-// Manager.compose(context, e, new FileOutputStream("C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge_Summary-DCI.out.ttl"), FhirFormat.TURTLE, OutputStyle.PRETTY, null);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- e.printStackTrace();
- throw e;
- }
- }
-
- @Ignore
- public void testEpic()
- throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
- Element e = Manager.parse(context,
- new FileInputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.xml"),
- FhirFormat.XML);
- Manager.compose(context, e,
- new FileOutputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.out.xml"),
- FhirFormat.XML, OutputStyle.PRETTY, null);
- Manager.compose(context, e,
- new FileOutputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.out.json"),
- FhirFormat.JSON, OutputStyle.PRETTY, null);
- Manager.compose(context, e,
- new FileOutputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-Discharge-Homework-Epic.out.ttl"),
- FhirFormat.TURTLE, OutputStyle.PRETTY, null);
- }
-
- @Ignore
- public void testDHIT()
- throws FHIRFormatError, DefinitionException, FileNotFoundException, IOException, FHIRException {
- Element e = Manager.parse(context,
- new FileInputStream("C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.xml"),
- FhirFormat.XML);
- Manager.compose(context, e,
- new FileOutputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.out.xml"),
- FhirFormat.XML, OutputStyle.PRETTY, null);
- Manager.compose(context, e,
- new FileOutputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.out.json"),
- FhirFormat.JSON, OutputStyle.PRETTY, null);
- Manager.compose(context, e,
- new FileOutputStream(
- "C:\\work\\org.hl7.fhir.test\\ccda-to-fhir-maps\\testdocuments\\IAT2-DS-Homework-DHIT.out.ttl"),
- FhirFormat.TURTLE, OutputStyle.PRETTY, null);
- }
+
}
\ No newline at end of file
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/OIDUtils.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/OIDUtils.java
index 0ac3d15c0..347208053 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/OIDUtils.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/OIDUtils.java
@@ -31,6 +31,9 @@ public class OIDUtils {
*/
public static String getUriForOid(String r) {
+ if (r == null) {
+ return null;
+ }
if (r.equals("2.16.840.1.113883.6.96"))
return "http://snomed.info/sct";
if (r.equals("2.16.840.1.113883.6.1"))
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java
index 1f9c48293..d7d14d4e6 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java
@@ -135,7 +135,10 @@ public class VersionUtilities {
if (version == null)
return null;
- if (Utilities.charCount(version, '.') == 2) {
+ if (Utilities.charCount(version, '.') == 1) {
+ String[] p = version.split("\\.");
+ return p[0]+"."+p[1];
+ } else if (Utilities.charCount(version, '.') == 2) {
String[] p = version.split("\\.");
return p[0]+"."+p[1];
} else {
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java
index 0fde15287..af0282ede 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java
@@ -31,7 +31,7 @@ public class ValidationOptions {
public boolean isGuessSystem() {
return guessSystem;
}
-
+
private ValidationOptions copy() {
ValidationOptions n = new ValidationOptions(language);
n.useServer = useServer;
diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java
index 6779ea132..48d16bca1 100644
--- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java
+++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java
@@ -84,6 +84,7 @@ import org.hl7.fhir.r5.model.ElementDefinition.ConstraintSeverity;
import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent;
+import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
import org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
@@ -112,6 +113,7 @@ import org.hl7.fhir.r5.model.SampledData;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
+import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.model.TimeType;
@@ -166,6 +168,7 @@ import ca.uhn.fhir.util.ObjectUtil;
public class InstanceValidator extends BaseValidator implements IResourceValidator {
+
public class ValidatorHostContext {
private Object appContext;
private Element container; // bundle, or parameters
@@ -1135,6 +1138,245 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return res;
}
+ private boolean checkTerminologyCodeableConcept(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, StructureDefinition logical) {
+ boolean res = true;
+ if (!noTerminologyChecks && 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()) {
+ ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl());
+ if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found by validator")) {
+ try {
+ CodeableConcept cc = convertToCodeableConcept(element, logical);
+ 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) {
+ if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
+ rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "No code provided, and a code must be provided from the value set " + describeReference(ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) + " (max value set " + valueset.getUrl()+")");
+ else
+ 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 {
+ long t = System.nanoTime();
+
+ // Check whether the codes are appropriate for the type of binding we have
+ boolean bindingsOk = true;
+ if (binding.getStrength() != BindingStrength.EXAMPLE) {
+ boolean atLeastOneSystemIsSupported = false;
+ for (Coding nextCoding : cc.getCoding()) {
+ String nextSystem = nextCoding.getSystem();
+ if (isNotBlank(nextSystem) && context.supportsSystem(nextSystem)) {
+ atLeastOneSystemIsSupported = true;
+ break;
+ }
+ }
+
+ if (!atLeastOneSystemIsSupported && binding.getStrength() == BindingStrength.EXAMPLE) {
+ // ignore this since we can't validate but it doesn't matter..
+ } else {
+ ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang), cc, valueset); // we're going to validate the codings directly
+ if (!vr.isOk()) {
+ bindingsOk = false;
+ if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
+ if (binding.getStrength() == BindingStrength.REQUIRED)
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Could not confirm that the codes provided are in the value set " + describeReference(binding.getValueSet()) + " and a code from this value set is required (class = "+vr.getErrorClass().toString()+")");
+ else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
+ if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
+ checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
+ else if (!noExtensibleWarnings)
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Could not confirm that the codes provided are in the value set " + describeReference(binding.getValueSet()) + " and a code should come from this value set unless it has no suitable code (class = "+vr.getErrorClass().toString()+")");
+ } else if (binding.getStrength() == BindingStrength.PREFERRED)
+ txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Could not confirm that the codes provided are in the value set " + describeReference(binding.getValueSet()) + " and a code is recommended to come from this value set (class = "+vr.getErrorClass().toString()+")");
+ } else {
+ if (binding.getStrength() == BindingStrength.REQUIRED)
+ txRule(errors, vr.getTxLink(), 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) (codes = "+ccSummary(cc)+")");
+ else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
+ if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
+ checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
+ if (!noExtensibleWarnings)
+ txWarning(errors, vr.getTxLink(), 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) (codes = "+ccSummary(cc)+")");
+ } else if (binding.getStrength() == BindingStrength.PREFERRED) {
+ txHint(errors, vr.getTxLink(), 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) (codes = "+ccSummary(cc)+")");
+ }
+ }
+ } else if (vr.getMessage()!=null) {
+ res = false;
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
+ } else {
+ res = false;
+ }
+ }
+ // Then, for any codes that are in code systems we are able
+ // to validate, we'll validate that the codes actually exist
+ if (bindingsOk) {
+ for (Coding nextCoding : cc.getCoding()) {
+ String nextCode = nextCoding.getCode();
+ String nextSystem = nextCoding.getSystem();
+ if (isNotBlank(nextCode) && isNotBlank(nextSystem) && context.supportsSystem(nextSystem)) {
+ ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang), nextSystem, nextCode, null);
+ if (!vr.isOk()) {
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Code {0} is not a valid code in code system {1}", nextCode, nextSystem);
+ }
+ }
+ }
+ }
+ txTime = txTime + (System.nanoTime() - t);
+ }
+ }
+ } catch (Exception e) {
+ warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Error "+e.getMessage()+" validating CodeableConcept");
+ }
+ // special case: if the logical model has both CodeableConcept and Coding mappings, we'll also check the first coding.
+ if (getMapping("http://hl7.org/fhir/terminology-pattern", logical, logical.getSnapshot().getElementFirstRep()).contains("Coding")) {
+ checkTerminologyCoding(errors, path, element, profile, theElementCntext, true, true, stack, logical);
+ }
+ }
+ } else if (binding.hasValueSet()) {
+ hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding by URI reference cannot be checked");
+ } else if (!noBindingMsgSuppressed) {
+ hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding for path " + path + " has no source, so can't be checked");
+ }
+ }
+ }
+ return res;
+ }
+
+ private void checkTerminologyCoding(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack, StructureDefinition logical) {
+ Coding c = convertToCoding(element, logical);
+ String code = c.getCode();
+ String system = c.getSystem();
+ String display = c.getDisplay();
+ rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, isAbsolute(system), "Coding.system must be an absolute reference, not a local reference");
+
+ if (system != null && code != null && !noTerminologyChecks) {
+ rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, !isValueSet(system), "The Coding references a value set, not a code system (\""+system+"\")");
+ try {
+ if (checkCode(errors, element, path, code, system, display, checkDisplay, stack))
+ 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")) {
+ if (binding.hasValueSet()) {
+ ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl());
+ if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found by validator")) {
+ try {
+ long t = System.nanoTime();
+ ValidationResult vr = null;
+ if (binding.getStrength() != BindingStrength.EXAMPLE) {
+ vr = context.validateCode(new ValidationOptions(stack.workingLang), c, valueset);
+ }
+ txTime = txTime + (System.nanoTime() - t);
+ if (vr != null && !vr.isOk()) {
+ if (vr.IsNoService())
+ txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "The value provided could not be validated in the absence of a terminology server");
+ else if (vr.getErrorClass() != null && !vr.getErrorClass().isInfrastructure()) {
+ if (binding.getStrength() == BindingStrength.REQUIRED)
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Could not confirm that 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) {
+ if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
+ checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), c, stack);
+ else if (!noExtensibleWarnings)
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Could not confirm that 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)
+ txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Could not confirm that the codes provided are in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code is recommended to come from this value set)");
+ } else if (binding.getStrength() == BindingStrength.REQUIRED)
+ txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "The Coding provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code is required from this value set)"+(vr.getMessage() != null ? " (error message = "+vr.getMessage()+")" : ""));
+ else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
+ if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
+ checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), c, stack);
+ else
+ txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "The Coding 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)"+(vr.getMessage() != null ? " (error message = "+vr.getMessage()+")" : ""));
+ } else if (binding.getStrength() == BindingStrength.PREFERRED)
+ txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "The Coding provided is not in the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl() + ", and a code is recommended to come from this value set)"+(vr.getMessage() != null ? " (error message = "+vr.getMessage()+")" : ""));
+ }
+ } catch (Exception e) {
+ warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Error "+e.getMessage()+" validating Coding");
+ }
+ }
+ } else if (binding.hasValueSet()) {
+ hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding by URI reference cannot be checked");
+ } else if (!inCodeableConcept && !noBindingMsgSuppressed) {
+ hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Binding for path " + path + " has no source, so can't be checked");
+ }
+ }
+ }
+ } catch (Exception e) {
+ rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Error "+e.getMessage()+" validating Coding: " + e.toString());
+ }
+ }
+ }
+
+ private CodeableConcept convertToCodeableConcept(Element element, StructureDefinition logical) {
+ CodeableConcept res = new CodeableConcept();
+ for (ElementDefinition ed : logical.getSnapshot().getElement()) {
+ if (Utilities.charCount(ed.getPath(), '.') == 1) {
+ List maps = getMapping("http://hl7.org/fhir/terminology-pattern", logical, ed);
+ for (String m : maps) {
+ String name = tail(ed.getPath());
+ List list = new ArrayList<>();
+ element.getNamedChildren(name, list);
+ if (!list.isEmpty()) {
+ if ("Coding.code".equals(m)) {
+ res.getCodingFirstRep().setCode(list.get(0).primitiveValue());
+ } else if ("Coding.system[fmt:OID]".equals(m)) {
+ String oid = list.get(0).primitiveValue();
+ String url = context.oid2Uri(oid);
+ if (url != null) {
+ res.getCodingFirstRep().setSystem(url);
+ } else {
+ res.getCodingFirstRep().setSystem("urn:oid:"+oid);
+ }
+ } else if ("Coding.version".equals(m)) {
+ res.getCodingFirstRep().setVersion(list.get(0).primitiveValue());
+ } else if ("Coding.display".equals(m)) {
+ res.getCodingFirstRep().setDisplay(list.get(0).primitiveValue());
+ } else if ("CodeableConcept.text".equals(m)) {
+ res.setText(list.get(0).primitiveValue());
+ } else if ("CodeableConcept.coding".equals(m)) {
+ StructureDefinition c = context.fetchTypeDefinition(ed.getTypeFirstRep().getCode());
+ for (Element e : list) {
+ res.addCoding(convertToCoding(e, c));
+ }
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+ private Coding convertToCoding(Element element, StructureDefinition logical) {
+ Coding res = new Coding();
+ for (ElementDefinition ed : logical.getSnapshot().getElement()) {
+ if (Utilities.charCount(ed.getPath(), '.') == 1) {
+ List maps = getMapping("http://hl7.org/fhir/terminology-pattern", logical, ed);
+ for (String m : maps) {
+ String name = tail(ed.getPath());
+ List list = new ArrayList<>();
+ element.getNamedChildren(name, list);
+ if (!list.isEmpty()) {
+ if ("Coding.code".equals(m)) {
+ res.setCode(list.get(0).primitiveValue());
+ } else if ("Coding.system[fmt:OID]".equals(m)) {
+ String oid = list.get(0).primitiveValue();
+ String url = context.oid2Uri(oid);
+ if (url != null) {
+ res.setSystem(url);
+ } else {
+ res.setSystem("urn:oid:"+oid);
+ }
+ } else if ("Coding.version".equals(m)) {
+ res.setVersion(list.get(0).primitiveValue());
+ } else if ("Coding.display".equals(m)) {
+ res.setDisplay(list.get(0).primitiveValue());
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+
private void checkMaxValueSet(List errors, String path, Element element, StructureDefinition profile, String maxVSUrl, CodeableConcept cc, NodeStack stack) {
// TODO Auto-generated method stub
ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl());
@@ -4194,7 +4436,18 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
} else if (type.equals("Resource")) {
validateContains(hostContext, errors, ei.path, ei.definition, definition, resource, ei.element, localStack, idStatusForEntry(element, ei)); // if
// (str.matches(".*([.,/])work\\1$"))
- }
+ } else if (Utilities.isAbsoluteUrl(type)) {
+ StructureDefinition defn = context.fetchTypeDefinition(type);
+ if (defn != null && hasMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep())) {
+ List txtype = getMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep());
+ if (txtype.contains("CodeableConcept")) {
+ checkTerminologyCodeableConcept(errors, ei.path, ei.element, profile, ei.definition, stack, defn);
+ thisIsCodeableConcept = true;
+ } else if (txtype.contains("Coding")) {
+ checkTerminologyCoding(errors, ei.path, ei.element, profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack, defn);
+ }
+ }
+ }
} else {
if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), ei.definition != null, "Unrecognised Content " + ei.name))
validateElement(hostContext, errors, profile, ei.definition, null, null, resource, ei.element, type, localStack, false, true);
@@ -4283,6 +4536,44 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
}
}
+ private boolean hasMapping(String url, StructureDefinition defn, ElementDefinition elem) {
+ String id = null;
+ for (StructureDefinitionMappingComponent m : defn.getMapping()) {
+ if (url.equals(m.getUri())) {
+ id = m.getIdentity();
+ break;
+ }
+ }
+ if (id != null) {
+ for (ElementDefinitionMappingComponent m : elem.getMapping()) {
+ if (id.equals(m.getIdentity())) {
+ return true;
+ }
+ }
+
+ }
+ return false;
+ }
+
+ private List getMapping(String url, StructureDefinition defn, ElementDefinition elem) {
+ List res = new ArrayList<>();
+ String id = null;
+ for (StructureDefinitionMappingComponent m : defn.getMapping()) {
+ if (url.equals(m.getUri())) {
+ id = m.getIdentity();
+ break;
+ }
+ }
+ if (id != null) {
+ for (ElementDefinitionMappingComponent m : elem.getMapping()) {
+ if (id.equals(m.getIdentity())) {
+ res.add(m.getMap());
+ }
+ }
+ }
+ return res;
+ }
+
public void checkMustSupport(StructureDefinition profile, ElementInfo ei) {
String usesMustSupport = profile.getUserString("usesMustSupport");
if (usesMustSupport == null) {
diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java
index 5f6c29155..0f2f1d2be 100644
--- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java
+++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java
@@ -23,11 +23,14 @@ import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
+import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.IResourceValidator.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy;
import org.hl7.fhir.r5.validation.InstanceValidator;
import org.hl7.fhir.r5.validation.ValidationEngine;
+import org.hl7.fhir.utilities.VersionUtilities;
+import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
@@ -72,7 +75,6 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
private String name;
private JsonObject content;
- private static String veVersion;
public ValidationTestSuite(String name, JsonObject content) {
this.name = name;
@@ -81,7 +83,8 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
private static final String DEF_TX = "http://tx.fhir.org";
// private static final String DEF_TX = "http://local.fhir.org:960";
- private static ValidationEngine ve;
+ private static Map ve = new HashMap<>();
+ private static ValidationEngine vCurr;
@SuppressWarnings("deprecation")
@Test
@@ -92,27 +95,28 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
if (content.has("version"))
v = content.get("version").getAsString();
- if (ve == null || !v.equals(veVersion)) {
+ v = VersionUtilities.getMajMin(v);
+ if (!ve.containsKey(v)) {
if (v.startsWith("5.0"))
- ve = new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, null, FhirPublication.R5, true);
+ ve.put(v, new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, null, FhirPublication.R5, true));
else if (v.startsWith("3.0"))
- ve = new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3, true);
+ ve.put(v, new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3, true));
else if (v.startsWith("4.0"))
- ve = new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4, true);
+ ve.put(v, new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4, true));
else if (v.startsWith("1.0"))
- ve = new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2, true);
+ ve.put(v, new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2, true));
else
throw new Exception("unknown version "+v);
- TestingUtilities.fcontext = ve.getContext();
- veVersion = v;
}
+ vCurr = ve.get(v);
+ TestingUtilities.fcontext = vCurr.getContext();
if (content.has("use-test") && !content.get("use-test").getAsBoolean())
return;
String testCaseContent = TestingUtilities.loadTestResource("validator", name.substring(name.indexOf(".")+1));
- InstanceValidator val = ve.getValidator();
+ InstanceValidator val = vCurr.getValidator();
val.setDebug(false);
if (content.has("allowed-extension-domain"))
val.getExtensionDomains().add(content.get("allowed-extension-domain").getAsString());
@@ -127,7 +131,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
if (content.has("questionnaire")) {
String filename = content.get("questionnaire").getAsString();
String contents = TestingUtilities.loadTestResource("validator", filename);
- ve.getContext().cacheResource(loadResource(filename, contents, v));
+ vCurr.getContext().cacheResource(loadResource(filename, contents, v));
}
if (content.has("codesystems")) {
for (JsonElement je : content.getAsJsonArray("codesystems")) {
@@ -152,7 +156,6 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
val.validate(null, errors, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.XML);
checkOutcomes(errors, content);
if (content.has("profile")) {
- List errorsProfile = new ArrayList();
JsonObject profile = content.getAsJsonObject("profile");
if (profile.has("supporting")) {
for (JsonElement e : profile.getAsJsonArray("supporting")) {
@@ -167,12 +170,37 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
System.out.println("Name: " + name+" - profile : "+profile.get("source").getAsString());
v = content.has("version") ? content.get("version").getAsString() : Constants.VERSION;
StructureDefinition sd = loadProfile(filename, contents, v, messages);
+ List errorsProfile = new ArrayList();
if (name.startsWith("Json."))
val.validate(null, errorsProfile, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.JSON, sd);
else
val.validate(null, errorsProfile, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.XML, sd);
checkOutcomes(errorsProfile, profile);
- }
+ }
+ if (content.has("logical")) {
+ JsonObject logical = content.getAsJsonObject("logical");
+ if (logical.has("supporting")) {
+ for (JsonElement e : logical.getAsJsonArray("supporting")) {
+ String filename = e.getAsString();
+ String contents = TestingUtilities.loadTestResource("validator", filename);
+ MetadataResource mr = (MetadataResource) loadResource(filename, contents, v);
+ if (mr instanceof StructureDefinition) {
+ val.getContext().generateSnapshot((StructureDefinition) mr, true);
+ }
+ val.getContext().cacheResource(mr);
+ }
+ }
+ List errorsLogical = new ArrayList();
+ Element le = val.validate(null, errorsLogical, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), (name.startsWith("Json.")) ? FhirFormat.JSON : FhirFormat.XML);
+ if (logical.has("expressions")) {
+ FHIRPathEngine fp = new FHIRPathEngine(val.getContext());
+ for (JsonElement e : logical.getAsJsonArray("expressions")) {
+ String exp = e.getAsString();
+ Assert.assertTrue(fp.evaluateToBoolean(null, le, le, le, fp.parse(exp)));
+ }
+ }
+ checkOutcomes(errorsLogical, logical);
+ }
}
public StructureDefinition loadProfile(String filename, String contents, String v, List messages) throws IOException, FHIRFormatError, FileNotFoundException, FHIRException, DefinitionException {
@@ -339,7 +367,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
@Override
public ValueSet resolveValueSet(Object appContext, String url) {
- return ve.getContext().fetchResource(ValueSet.class, url);
+ return vCurr.getContext().fetchResource(ValueSet.class, url);
}
}