Merge pull request #1460 from hapifhir/2023-10-gg-choice-groups
2023 10 gg choice groups
This commit is contained in:
commit
e2b3e1557f
|
@ -158,7 +158,7 @@ public class PECodeGenerator {
|
|||
w(b, " return theThing;");
|
||||
w(b, " }");
|
||||
w(b);
|
||||
jdoc(b, "Save this profile class into an existing resource (overwriting enything that exists in the profile) ", 2, true);
|
||||
jdoc(b, "Save this profile class into an existing resource (overwriting anything that exists in the profile) ", 2, true);
|
||||
w(b, " public void save(IWorkerContext context, "+base+" dest, boolean nulls) {");
|
||||
w(b, " workerContext = context;");
|
||||
w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
|
||||
|
|
|
@ -1,275 +0,0 @@
|
|||
package org.hl7.fhir.r4b.test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4b.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4b.elementmodel.Element;
|
||||
import org.hl7.fhir.r4b.elementmodel.Manager;
|
||||
import org.hl7.fhir.r4b.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r4b.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4b.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4b.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r4b.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.ToolsVersion;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class CDARoundTripTests {
|
||||
|
||||
private static SimpleWorkerContext context;
|
||||
private static FHIRPathEngine fp;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() throws Exception {
|
||||
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(
|
||||
org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager.FilesystemPackageCacheMode.USER);
|
||||
context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1"));
|
||||
fp = new FHIRPathEngine(context);
|
||||
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "any.xml"), "any.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ii.xml"), "ii.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cd.xml"), "cd.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ce.xml"), "ce.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ed.xml"), "ed.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "st.xml"), "st.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
//
|
||||
//// <typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040"/>
|
||||
//// assertEquals("POCD_HD000040", fp.evaluateToString(e, "typeId.extension"));
|
||||
//// assertEquals("2.16.840.1.113883.1.3", fp.evaluateToString(e, "typeId.root"));
|
||||
//// <templateId root="2.16.840.1.113883.3.27.1776"/>
|
||||
//// assertEquals("2.16.840.1.113883.3.27.1776", fp.evaluateToString(e, "templateId.root"));
|
||||
//// <id extension="c266" root="2.16.840.1.113883.19.4"/>
|
||||
// assertEquals("2.16.840.1.113883.19.4", fp.evaluateToString(e, "id.root"));
|
||||
// assertEquals("c266", fp.evaluateToString(e, "id.extension"));
|
||||
//
|
||||
//// <title>Good Health Clinic Consultation Note</title>
|
||||
// assertEquals("Good Health Clinic Consultation Note", fp.evaluateToString(e, "title.dataString"));
|
||||
//// <effectiveTime value="20000407"/>
|
||||
// assertEquals("2000-04-07", fp.evaluateToString(e, "effectiveTime.value"));
|
||||
//// <confidentialityCode code="N" codeSystem="2.16.840.1.113883.5.25"/>
|
||||
// assertEquals("N", fp.evaluateToString(e, "confidentialityCode.code"));
|
||||
// assertEquals("2.16.840.1.113883.5.25", fp.evaluateToString(e, "confidentialityCode.codeSystem"));
|
||||
//// <languageCode code="en-US"/>
|
||||
// assertEquals("en-US", fp.evaluateToString(e, "languageCode.code"));
|
||||
//// <setId extension="BB35" root="2.16.840.1.113883.19.7"/>
|
||||
// assertEquals("BB35", fp.evaluateToString(e, "setId.extension"));
|
||||
// assertEquals("2.16.840.1.113883.19.7", fp.evaluateToString(e, "setId.root"));
|
||||
//// <versionNumber value="2"/>
|
||||
// assertEquals("2", fp.evaluateToString(e, "versionNumber.value"));
|
||||
//// <recordTarget>
|
||||
//// <patientRole>
|
||||
//// <id extension="12345" root="2.16.840.1.113883.19.5"/>
|
||||
// assertEquals("12345", fp.evaluateToString(e, "recordTarget.patientRole.id.extension"));
|
||||
// assertEquals("2.16.840.1.113883.19.5", fp.evaluateToString(e, "recordTarget.patientRole.id.root"));
|
||||
//// <patient>
|
||||
//// <name>
|
||||
//// <family>Levin</family>
|
||||
// assertEquals("Levin", fp.evaluateToString(e, "recordTarget.patientRole.patient.name.family.dataString"));
|
||||
//// <given>Henry</given>
|
||||
// assertEquals("Henry", fp.evaluateToString(e, "recordTarget.patientRole.patient.name.given.dataString"));
|
||||
//// <suffix>the 7th</suffix>
|
||||
//// </name>
|
||||
//// <administrativeGenderCode code="M" codeSystem="2.16.840.1.113883.5.1"/>
|
||||
//// <birthTime value="19320924"/>
|
||||
//// </patient>
|
||||
//// <providerOrganization>
|
||||
//// <id root="2.16.840.1.113883.19.5"/>
|
||||
//// </providerOrganization>
|
||||
//// </patientRole>
|
||||
//// </recordTarget>
|
||||
//
|
||||
//// <component>
|
||||
//// <structuredBody>
|
||||
//// <component>
|
||||
//// <section>
|
||||
//
|
||||
//// <component>
|
||||
//// <section>
|
||||
//// <code code="8709-8" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
|
||||
//// <title>Skin Exam</title>
|
||||
//// <text>Erythematous rash, palmar surface, left index finger.
|
||||
//// <renderMultiMedia referencedObject="MM1"/>
|
||||
//// </text>
|
||||
//
|
||||
// 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"));
|
||||
// // <div>Erythematous rash, palmar surface, left index finger.
|
||||
// // <img src="MM1"/></div>
|
||||
// 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("<img src=\"MM1\"/>"));
|
||||
// } 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(Utilities.path("[tmp]", "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);
|
||||
// }
|
||||
|
||||
public void assertsExample(Element cdaExample) {
|
||||
Assertions.assertEquals("2.16.840.1.113883.3.27.1776",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.templateId.root")));
|
||||
Assertions.assertEquals("SoEN",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.displayName")));
|
||||
Assertions.assertEquals("SoEN2", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample,
|
||||
fp.parse("ClinicalDocument.code.sdtcDisplayName")));
|
||||
Assertions.assertEquals("c266",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.id.extension")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.19.4",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.id.root")));
|
||||
Assertions.assertEquals("X-34133-9",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.code")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.6.1",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.codeSystem")));
|
||||
Assertions.assertEquals("LOINC", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample,
|
||||
fp.parse("ClinicalDocument.code.codeSystemName")));
|
||||
Assertions.assertEquals("Episode Note",
|
||||
fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.title.dataString")));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Deserializes a simplified CDA example into the logical model and checks that
|
||||
* xml deserialization/serialization
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void testClinicalDocumentXmlParser() throws IOException {
|
||||
Element cda = Manager.parseSingle(context,
|
||||
TestingUtilities.loadTestResourceStream("validator", "cda", "example.xml"), FhirFormat.XML);
|
||||
|
||||
assertsExample(cda);
|
||||
|
||||
ByteArrayOutputStream baosXml = new ByteArrayOutputStream();
|
||||
Manager.compose(context, cda, baosXml, FhirFormat.XML, OutputStyle.PRETTY, null);
|
||||
Element cdaXmlRoundtrip = Manager.parseSingle(context, new ByteArrayInputStream(baosXml.toString().getBytes()),
|
||||
FhirFormat.XML);
|
||||
assertsExample(cdaXmlRoundtrip);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Deserializes a simplified CDA example into the logical model and checks that
|
||||
* json deserialization/serialization works
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void testClinicalDocumentJsonParser() throws IOException {
|
||||
Element cda = Manager.parseSingle(context,
|
||||
TestingUtilities.loadTestResourceStream("validator", "cda", "example.xml"), FhirFormat.XML);
|
||||
|
||||
assertsExample(cda);
|
||||
|
||||
ByteArrayOutputStream baosJson = new ByteArrayOutputStream();
|
||||
Manager.compose(context, cda, baosJson, FhirFormat.JSON, OutputStyle.PRETTY, null);
|
||||
Element cdaJsonRoundtrip = Manager.parseSingle(context, new ByteArrayInputStream(baosJson.toString().getBytes()),
|
||||
FhirFormat.JSON);
|
||||
|
||||
assertsExample(cdaJsonRoundtrip);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* verify that umlaut like äö etc are not encoded in UTF-8 in attributes
|
||||
*/
|
||||
public void testSerializeUmlaut() throws IOException {
|
||||
Element xml = Manager.parseSingle(context,
|
||||
TestingUtilities.loadTestResourceStream("validator", "cda", "example.xml"), FhirFormat.XML);
|
||||
|
||||
List<Element> title = xml.getChildrenByName("title");
|
||||
Assertions.assertTrue(title != null && title.size() == 1);
|
||||
|
||||
Element value = title.get(0).getChildren().get(0);
|
||||
Assertions.assertEquals("Episode Note", value.getValue());
|
||||
value.setValue("öé");
|
||||
|
||||
ByteArrayOutputStream baosXml = new ByteArrayOutputStream();
|
||||
Manager.compose(TestingUtilities.context(), xml, baosXml, FhirFormat.XML, OutputStyle.PRETTY, null);
|
||||
String cdaSerialised = baosXml.toString("UTF-8");
|
||||
Assertions.assertTrue(cdaSerialised.indexOf("öé") > 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -34,6 +34,11 @@ import java.io.File;
|
|||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -43,6 +48,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Getter;
|
||||
|
@ -74,11 +80,13 @@ import org.hl7.fhir.r5.model.ElementDefinition;
|
|||
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
import org.hl7.fhir.r5.model.ImplementationGuide;
|
||||
import org.hl7.fhir.r5.model.Library;
|
||||
import org.hl7.fhir.r5.model.Measure;
|
||||
import org.hl7.fhir.r5.model.NamingSystem;
|
||||
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemIdentifierType;
|
||||
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemType;
|
||||
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemUniqueIdComponent;
|
||||
import org.hl7.fhir.r5.model.OperationDefinition;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
|
@ -133,20 +141,36 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nBase;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.json.JsonException;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonProperty;
|
||||
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext {
|
||||
|
||||
class OIDSource {
|
||||
private String folder;
|
||||
private Connection db;
|
||||
protected OIDSource(String folder) {
|
||||
super();
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final boolean QA_CHECK_REFERENCE_SOURCE = false; // see comments below
|
||||
|
||||
public class ResourceProxy {
|
||||
public static class ResourceProxy {
|
||||
private Resource resource;
|
||||
private CanonicalResourceProxy proxy;
|
||||
|
||||
|
@ -241,7 +265,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
private UcumService ucumService;
|
||||
protected Map<String, byte[]> binaries = new HashMap<String, byte[]>();
|
||||
protected Map<String, String> oidCache = new HashMap<>();
|
||||
protected Map<String, Set<String>> oidCacheManual = new HashMap<>();
|
||||
protected List<OIDSource> oidSources = new ArrayList<>();
|
||||
|
||||
protected Map<String, Map<String, ValidationResult>> validationCache = new HashMap<String, Map<String,ValidationResult>>();
|
||||
protected String name;
|
||||
|
@ -323,7 +348,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
codeSystemsUsed.addAll(other.codeSystemsUsed);
|
||||
ucumService = other.ucumService;
|
||||
binaries.putAll(other.binaries);
|
||||
oidCache.putAll(other.oidCache);
|
||||
oidSources.addAll(other.oidSources);
|
||||
oidCacheManual.putAll(other.oidCacheManual);
|
||||
validationCache.putAll(other.validationCache);
|
||||
tlogging = other.tlogging;
|
||||
locator = other.locator;
|
||||
|
@ -446,7 +472,38 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
|
||||
if (r instanceof CodeSystem || r instanceof NamingSystem) {
|
||||
oidCache.clear();
|
||||
String url = null;
|
||||
Set<String> oids = new HashSet<String>();
|
||||
if (r instanceof CodeSystem) {
|
||||
CodeSystem cs = (CodeSystem) r;
|
||||
url = cs.getUrl();
|
||||
for (Identifier id : cs.getIdentifier()) {
|
||||
if (id.hasValue() && id.getValue().startsWith("urn:oid:")) {
|
||||
oids.add(id.getValue().substring(8));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (r instanceof NamingSystem) {
|
||||
NamingSystem ns = ((NamingSystem) r);
|
||||
if (ns.getKind() == NamingSystemType.CODESYSTEM) {
|
||||
for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) {
|
||||
if (id.getType() == NamingSystemIdentifierType.URI) {
|
||||
url = id.getValue();
|
||||
}
|
||||
if (id.getType() == NamingSystemIdentifierType.OID) {
|
||||
oids.add(id.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (url != null) {
|
||||
for (String s : oids) {
|
||||
if (!oidCacheManual.containsKey(s)) {
|
||||
oidCacheManual.put(s, new HashSet<>());
|
||||
}
|
||||
oidCacheManual.get(s).add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (r instanceof CanonicalResource) {
|
||||
|
@ -2778,4 +2835,57 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
this.cachingAllowed = cachingAllowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> urlsForOid(boolean codeSystem, String oid) {
|
||||
if (oid == null) {
|
||||
return null;
|
||||
}
|
||||
Set<String> urls = new HashSet<>();
|
||||
if (oidCacheManual.containsKey(oid)) {
|
||||
urls.addAll(oidCacheManual.get(oid));
|
||||
}
|
||||
for (OIDSource os : oidSources) {
|
||||
if (os.db == null) {
|
||||
os.db = connectToOidSource(os.folder);
|
||||
}
|
||||
if (os.db != null) {
|
||||
try {
|
||||
PreparedStatement psql = os.db.prepareStatement("Select URL from OIDMap where OID = ?");
|
||||
psql.setString(1, oid);
|
||||
ResultSet rs = psql.executeQuery();
|
||||
while (rs.next()) {
|
||||
urls.add(rs.getString(1));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// nothing, there would alreagy have been an error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (oid) {
|
||||
case "2.16.840.1.113883.6.1" :
|
||||
urls.add("http://loinc.org");
|
||||
break;
|
||||
case "2.16.840.1.113883.6.96" :
|
||||
urls.add("http://snomed.info/sct");
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
private Connection connectToOidSource(String folder) {
|
||||
try {
|
||||
File ff = new File(folder);
|
||||
File of = new File(Utilities.path(ff.getAbsolutePath(), ".oids.db"));
|
||||
if (!of.exists()) {
|
||||
OidIndexBuilder oidBuilder = new OidIndexBuilder(ff, of);
|
||||
oidBuilder.build();
|
||||
}
|
||||
return DriverManager.getConnection("jdbc:sqlite:"+of.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1034,5 +1034,6 @@ public interface IWorkerContext {
|
|||
public boolean isForPublication();
|
||||
public void setForPublication(boolean value);
|
||||
|
||||
public Set<String> urlsForOid(boolean codeSystem, String oid);
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package org.hl7.fhir.r5.context;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||
|
||||
public class OidIndexBuilder {
|
||||
|
||||
private File folder;
|
||||
private File target;
|
||||
|
||||
public OidIndexBuilder(File ff, File of) {
|
||||
super();
|
||||
this.folder = ff;
|
||||
this.target = of;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
System.out.println("Generate OID index for "+folder.getAbsolutePath());
|
||||
target.delete();
|
||||
try {
|
||||
Set<String> matches = new HashSet<String>();
|
||||
|
||||
Connection db = DriverManager.getConnection("jdbc:sqlite:"+target.getAbsolutePath());
|
||||
Statement stmt = db.createStatement();
|
||||
stmt.execute("CREATE TABLE OIDMap (\r\n"+
|
||||
"OID nvarchar NOT NULL,\r\n"+
|
||||
"URL nvarchar NOT NULL,\r\n"+
|
||||
"PRIMARY KEY (OID, URL))\r\n");
|
||||
|
||||
PreparedStatement psql = db.prepareStatement("Insert into OIDMap (OID, URL) values (?, ?)");;
|
||||
for (File f : folder.listFiles()) {
|
||||
if (!f.getName().startsWith(".") && f.getName().endsWith(".json")) {
|
||||
try {
|
||||
JsonObject json = JsonParser.parseObject(f);
|
||||
processFile(psql, matches, json);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error processing "+f.getAbsolutePath()+" while generating OIDs: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
db.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error processing "+folder.getAbsolutePath()+" while generating OIDs: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void processFile(PreparedStatement psql, Set<String> matches, JsonObject json) throws SQLException {
|
||||
String rt = json.asString("resourceType");
|
||||
if (rt != null) {
|
||||
Set<String> oids = new HashSet<String>();
|
||||
String url = null;
|
||||
if ("NamingSystem".equals(rt)) {
|
||||
for (JsonObject id : json.getJsonObjects("uniqueId")) {
|
||||
String t = id.asString("type");
|
||||
String v = id.asString("value");
|
||||
if ("url".equals(t) && v != null) {
|
||||
url = v;
|
||||
} else if ("oid".equals(t) && v != null) {
|
||||
oids.add(v);
|
||||
}
|
||||
}
|
||||
if (url != null) {
|
||||
for (String s : oids) {
|
||||
addOid(psql, matches, s, url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (json.hasPrimitive("url")) {
|
||||
url = json.asString("url");
|
||||
if (json.has("oid")) {
|
||||
oids.add(json.asString("oid"));
|
||||
}
|
||||
if (json.has("url")) {
|
||||
String v = json.asString("url");
|
||||
if (v != null && v.startsWith("urn:oid:")) {
|
||||
oids.add(v.substring(8));
|
||||
}
|
||||
}
|
||||
|
||||
for (JsonObject id : json.getJsonObjects("identifier")) {
|
||||
String v = id.asString("value");
|
||||
if (v != null && v.startsWith("urn:oid:")) {
|
||||
oids.add(v.substring(8));
|
||||
}
|
||||
}
|
||||
if (!oids.isEmpty()) {
|
||||
for (String s : oids) {
|
||||
addOid(psql, matches, s, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addOid(PreparedStatement psql, Set<String> matches, String oid, String url) throws SQLException {
|
||||
String key = oid+"@"+url;
|
||||
if (!matches.contains(key)) {
|
||||
matches.add(key);
|
||||
psql.setString(1, oid);
|
||||
psql.setString(2, url);
|
||||
psql.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -482,6 +482,11 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
packageTracker.packageLoaded(pi.id(), pi.version());
|
||||
}
|
||||
|
||||
String of = pi.getFolders().get("package").getFolderPath();
|
||||
if (of != null) {
|
||||
oidSources.add(new OIDSource(of));
|
||||
}
|
||||
|
||||
if ((types == null || types.size() == 0) && loader != null) {
|
||||
types = loader.getTypes();
|
||||
}
|
||||
|
@ -803,5 +808,6 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
return VersionUtilities.getSpecUrl(getVersion())+"/";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -101,22 +102,23 @@ public class JsonParser extends ParserBase {
|
|||
this.profileUtilities = new ProfileUtilities(this.context, null, null, new FHIRPathEngine(context));
|
||||
contextUtilities = new ContextUtilities(context);
|
||||
}
|
||||
//
|
||||
// public Element parse(String source, String type) throws Exception {
|
||||
// JsonObject obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true);
|
||||
// String path = "/"+type;
|
||||
// StructureDefinition sd = getDefinition(-1, -1, type);
|
||||
// if (sd == null)
|
||||
// return null;
|
||||
//
|
||||
// Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)).setFormat(FhirFormat.JSON);
|
||||
// result.setPath(type);
|
||||
// checkObject(obj, result, path);
|
||||
// result.setType(type);
|
||||
// parseChildren(path, obj, result, true);
|
||||
// result.numberChildren();
|
||||
// return result;
|
||||
// }
|
||||
|
||||
public Element parse(String source, String type) throws Exception {
|
||||
ValidatedFragment focusFragment = new ValidatedFragment(ValidatedFragment.FOCUS_NAME, "json", source.getBytes(StandardCharsets.UTF_8), false);
|
||||
JsonObject obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true);
|
||||
String path = "/"+type;
|
||||
StructureDefinition sd = getDefinition(focusFragment.getErrors(), -1, -1, type);
|
||||
if (sd == null)
|
||||
return null;
|
||||
|
||||
Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)).setFormat(FhirFormat.JSON);
|
||||
result.setPath(type);
|
||||
checkObject(focusFragment.getErrors(), obj, result, path);
|
||||
result.setType(type);
|
||||
parseChildren(focusFragment.getErrors(), path, obj, result, true, new ArrayList<>());
|
||||
result.numberChildren();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
|
|
|
@ -609,5 +609,15 @@ public class Property {
|
|||
return ok;
|
||||
}
|
||||
|
||||
|
||||
public String getXmlTypeName() {
|
||||
TypeRefComponent tr = type;
|
||||
if (tr == null) {
|
||||
tr = definition.getTypeFirstRep();
|
||||
}
|
||||
StructureDefinition sd = context.fetchTypeDefinition(tr.getWorkingCode());
|
||||
return sd.getSnapshot().getElementFirstRep().getPath();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -232,7 +232,7 @@ public class XmlParser extends ParserBase {
|
|||
|
||||
Element result = new Element(element.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.XML);
|
||||
result.setPath(element.getLocalName());
|
||||
checkElement(errors, element, path, result.getProperty());
|
||||
checkElement(errors, element, path, result.getProperty(), false);
|
||||
result.markLocation(line(element, false), col(element, false));
|
||||
result.setType(element.getLocalName());
|
||||
parseChildren(errors, path, element, result);
|
||||
|
@ -274,7 +274,7 @@ public class XmlParser extends ParserBase {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void checkElement(List<ValidationMessage> errors, org.w3c.dom.Element element, String path, Property prop) throws FHIRFormatError {
|
||||
private void checkElement(List<ValidationMessage> errors, org.w3c.dom.Element element, String path, Property prop, boolean xsiTypeChecked) throws FHIRFormatError {
|
||||
if (policy == ValidationPolicy.EVERYTHING) {
|
||||
if (empty(element) && FormatUtilities.FHIR_NS.equals(element.getNamespaceURI())) // this rule only applies to FHIR Content
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.ELEMENT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR);
|
||||
|
@ -283,8 +283,20 @@ public class XmlParser extends ParserBase {
|
|||
if (elementNs == null) {
|
||||
elementNs = "noNamespace";
|
||||
}
|
||||
if (!elementNs.equals(ns))
|
||||
if (!elementNs.equals(ns)) {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.WRONG_NAMESPACE__EXPECTED_, ns), IssueSeverity.ERROR);
|
||||
}
|
||||
if (!xsiTypeChecked) {
|
||||
String xsiType = element.getAttributeNS(FormatUtilities.NS_XSI, "type");
|
||||
if (!Utilities.noString(xsiType)) {
|
||||
String actualType = prop.getXmlTypeName();
|
||||
if (!xsiType.equals(actualType)) {
|
||||
logError(errors, "2023-10-12", line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.XSI_TYPE_WRONG, xsiType, actualType), IssueSeverity.ERROR);
|
||||
} else {
|
||||
logError(errors, "2023-10-12", line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.XSI_TYPE_UNNECESSARY), IssueSeverity.INFORMATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,7 +305,7 @@ public class XmlParser extends ParserBase {
|
|||
Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.XML);
|
||||
result.setPath(base.getLocalName());
|
||||
String path = "/"+pathPrefix(base.getNamespaceURI())+base.getLocalName();
|
||||
checkElement(errors, base, path, result.getProperty());
|
||||
checkElement(errors, base, path, result.getProperty(), false);
|
||||
result.setType(base.getLocalName());
|
||||
parseChildren(errors, path, base, result);
|
||||
result.numberChildren();
|
||||
|
@ -304,8 +316,10 @@ public class XmlParser extends ParserBase {
|
|||
// this parsing routine retains the original order in a the XML file, to support validation
|
||||
reapComments(node, element);
|
||||
List<Property> properties = element.getProperty().getChildProperties(element.getName(), XMLUtil.getXsiType(node));
|
||||
Property cgProp = getChoiceGroupProp(properties);
|
||||
Property mtProp = cgProp == null ? null : getTextProp(cgProp.getChildProperties(null, null));
|
||||
|
||||
String text = XMLUtil.getDirectText(node).trim();
|
||||
String text = mtProp == null ? XMLUtil.getDirectText(node).trim() : null;
|
||||
int line = line(node, false);
|
||||
int col = col(node, false);
|
||||
if (!Utilities.noString(text)) {
|
||||
|
@ -396,6 +410,7 @@ public class XmlParser extends ParserBase {
|
|||
while (child != null) {
|
||||
if (child.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Property property = getElementProp(properties, child.getLocalName(), child.getNamespaceURI());
|
||||
|
||||
if (property != null) {
|
||||
if (property.getName().equals(lastName)) {
|
||||
repeatCount++;
|
||||
|
@ -431,7 +446,7 @@ public class XmlParser extends ParserBase {
|
|||
} else {
|
||||
n.setPath(element.getPath()+"."+property.getName());
|
||||
}
|
||||
checkElement(errors, (org.w3c.dom.Element) child, npath, n.getProperty());
|
||||
boolean xsiTypeChecked = false;
|
||||
boolean ok = true;
|
||||
if (property.isChoice()) {
|
||||
if (property.getDefinition().hasRepresentation(PropertyRepresentation.TYPEATTR)) {
|
||||
|
@ -450,9 +465,11 @@ public class XmlParser extends ParserBase {
|
|||
n.setType(xsiType);
|
||||
n.setExplicitType(xsiType);
|
||||
}
|
||||
xsiTypeChecked = true;
|
||||
} else
|
||||
n.setType(n.getType());
|
||||
}
|
||||
checkElement(errors, (org.w3c.dom.Element) child, npath, n.getProperty(), xsiTypeChecked);
|
||||
element.getChildren().add(n);
|
||||
if (ok) {
|
||||
if (property.isResource())
|
||||
|
@ -462,9 +479,57 @@ public class XmlParser extends ParserBase {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName(), path), IssueSeverity.ERROR);
|
||||
if (cgProp != null) {
|
||||
property = getElementProp(cgProp.getChildProperties(null, null), child.getLocalName(), child.getNamespaceURI());
|
||||
if (property != null) {
|
||||
if (cgProp.getName().equals(lastName)) {
|
||||
repeatCount++;
|
||||
} else {
|
||||
lastName = cgProp.getName();
|
||||
repeatCount = 0;
|
||||
}
|
||||
|
||||
String npath = path+"/"+pathPrefix(cgProp.getXmlNamespace())+cgProp.getName();
|
||||
String name = cgProp.getName();
|
||||
Element cgn = new Element(cgProp.getName(), cgProp).setFormat(FhirFormat.XML);
|
||||
cgn.setPath(element.getPath()+"."+cgProp.getName()+"["+repeatCount+"]");
|
||||
element.getChildren().add(cgn);
|
||||
|
||||
npath = npath+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName();
|
||||
name = child.getLocalName();
|
||||
Element n = new Element(name, property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML);
|
||||
cgn.getChildren().add(n);
|
||||
n.setPath(element.getPath()+"."+property.getName());
|
||||
checkElement(errors, (org.w3c.dom.Element) child, npath, n.getProperty(), false);
|
||||
parseChildren(errors, npath, (org.w3c.dom.Element) child, n);
|
||||
}
|
||||
}
|
||||
if (property == null) {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName(), path), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
} else if (child.getNodeType() == Node.CDATA_SECTION_NODE){
|
||||
} else if (child.getNodeType() == Node.TEXT_NODE && !Utilities.noString(child.getTextContent().trim()) && mtProp != null) {
|
||||
if (cgProp.getName().equals(lastName)) {
|
||||
repeatCount++;
|
||||
} else {
|
||||
lastName = cgProp.getName();
|
||||
repeatCount = 0;
|
||||
}
|
||||
|
||||
String npath = path+"/"+pathPrefix(cgProp.getXmlNamespace())+cgProp.getName();
|
||||
String name = cgProp.getName();
|
||||
Element cgn = new Element(cgProp.getName(), cgProp).setFormat(FhirFormat.XML);
|
||||
cgn.setPath(element.getPath()+"."+cgProp.getName()+"["+repeatCount+"]");
|
||||
element.getChildren().add(cgn);
|
||||
|
||||
npath = npath+"/text()";
|
||||
name = mtProp.getName();
|
||||
Element n = new Element(name, mtProp, mtProp.getType(), child.getTextContent().trim()).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML);
|
||||
cgn.getChildren().add(n);
|
||||
n.setPath(element.getPath()+"."+mtProp.getName());
|
||||
|
||||
|
||||
} else if (child.getNodeType() == Node.CDATA_SECTION_NODE) {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.CDATA_IS_NOT_ALLOWED), IssueSeverity.ERROR);
|
||||
} else if (!Utilities.existsInList(child.getNodeType(), 3, 8)) {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NODE_TYPE__IS_NOT_ALLOWED, Integer.toString(child.getNodeType())), IssueSeverity.ERROR);
|
||||
|
@ -473,6 +538,15 @@ public class XmlParser extends ParserBase {
|
|||
}
|
||||
}
|
||||
|
||||
private Property getChoiceGroupProp(List<Property> properties) {
|
||||
for (Property p : properties) {
|
||||
if (p.getDefinition().hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean validAttrValue(String value) {
|
||||
if (version == null) {
|
||||
return true;
|
||||
|
@ -515,6 +589,8 @@ public class XmlParser extends ParserBase {
|
|||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ public class PECodeGenerator {
|
|||
w(b, " return theThing;");
|
||||
w(b, " }");
|
||||
w(b);
|
||||
jdoc(b, "Save this profile class into an existing resource (overwriting enything that exists in the profile) ", 2, true);
|
||||
jdoc(b, "Save this profile class into an existing resource (overwriting anything that exists in the profile) ", 2, true);
|
||||
w(b, " public void save(IWorkerContext context, "+base+" dest, boolean nulls) {");
|
||||
w(b, " workerContext = context;");
|
||||
w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
|
||||
|
|
|
@ -95,69 +95,6 @@ import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
|||
|
||||
public class StructureDefinitionRenderer extends ResourceRenderer {
|
||||
|
||||
// public class ObligationWrapper {
|
||||
//
|
||||
// private Extension ext;
|
||||
//
|
||||
// public ObligationWrapper(Extension ext) {
|
||||
// this.ext = ext;
|
||||
// }
|
||||
//
|
||||
// public boolean hasActor() {
|
||||
// return ext.hasExtension("actor");
|
||||
// }
|
||||
//
|
||||
// public boolean hasActor(String id) {
|
||||
// return ext.hasExtension("actor") && id.equals(ext.getExtensionByUrl("actor").getValue().primitiveValue());
|
||||
// }
|
||||
//
|
||||
// public Coding getCode() {
|
||||
// Extension code = ext.getExtensionByUrl("obligation");
|
||||
// if (code != null && code.hasValueCoding()) {
|
||||
// return code.getValueCoding();
|
||||
// }
|
||||
// if (code != null && code.hasValueCodeType()) {
|
||||
// return new Coding().setSystem("http://hl7.org/fhir/tools/CodeSystem/obligation").setCode(code.getValueCodeType().primitiveValue());
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public boolean hasFilter() {
|
||||
// return ext.hasExtension("filter");
|
||||
// }
|
||||
//
|
||||
// public String getFilter() {
|
||||
// Extension code = ext.getExtensionByUrl("filter");
|
||||
// if (code != null && code.getValue() != null) {
|
||||
// return code.getValue().primitiveValue();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public boolean hasUsage() {
|
||||
// return ext.hasExtension("usage");
|
||||
// }
|
||||
//
|
||||
// public String getFilterDocumentation() {
|
||||
// Extension code = ext.getExtensionByUrl("filter-desc");
|
||||
// if (code != null && code.getValue() != null) {
|
||||
// return code.getValue().primitiveValue();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public List<UsageContext> getUsage() {
|
||||
// List<UsageContext> usage = new ArrayList<>();
|
||||
// for (Extension u : ext.getExtensionsByUrl("usage" )) {
|
||||
// if (u.hasValueUsageContext()) {
|
||||
// usage.add(u.getValueUsageContext());
|
||||
// }
|
||||
// }
|
||||
// return usage;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
public class SourcedElementDefinition {
|
||||
private StructureDefinition profile;
|
||||
private ElementDefinition definition;
|
||||
|
@ -1473,6 +1410,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
c.getPieces().add(gen.new Piece(null, "An ID is not allowed in this context", null));
|
||||
}
|
||||
}
|
||||
if (definition.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) {
|
||||
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
|
||||
c.getPieces().add(gen.new Piece(null, translate("sd.table", "Choice Group")+": ", null).addStyle("font-weight:bold"));
|
||||
c.getPieces().add(gen.new Piece(null, "This is a repeating choice group that does not appear directly in the instance", null));
|
||||
}
|
||||
if (definition.hasExtension(ToolingExtensions.EXT_XML_NAME)) {
|
||||
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
|
||||
if (definition.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE)) {
|
||||
|
@ -3663,6 +3605,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
tableRow(tbl, "ID Expectation", null, strikethrough, "An ID is not allowed in this context");
|
||||
}
|
||||
}
|
||||
|
||||
if (d.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) {
|
||||
tableRow(tbl, "Choice Group", null, strikethrough, "This is a repeating choice group that does not appear directly in the instance");
|
||||
}
|
||||
|
||||
// tooling extensions for formats
|
||||
if (ToolingExtensions.hasExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE,
|
||||
ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) {
|
||||
|
|
|
@ -255,7 +255,8 @@ public class ToolingExtensions {
|
|||
public static final String EXT_OBLIGATION_TOOLS = "http://hl7.org/fhir/tools/StructureDefinition/obligation";
|
||||
public static final String EXT_OBLIGATION_CORE = "http://hl7.org/fhir/StructureDefinition/obligation";
|
||||
public static final String EXT_NO_BINDING = "http://hl7.org/fhir/tools/StructureDefinition/no-binding";
|
||||
;
|
||||
public static final String EXT_ID_CHOICE_GROUP = "http://hl7.org/fhir/tools/StructureDefinition/xml-choice-group";
|
||||
public static final String EXT_DATE_RULES = "http://hl7.org/fhir/tools/StructureDefinition/elementdefinition-date-rules";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ public class TestProfile extends PEGeneratedBase {
|
|||
private String id; //
|
||||
private List<Extension> extensions = new ArrayList<>(); // Extension
|
||||
private String simple; // A simple extension
|
||||
// @ProfileAnnotation(max = 1, min=1, path="Observation.extension('url')", doco = "blah", type="")
|
||||
private TestComplexExtension complex; // A complex extension
|
||||
private Identifier identifier; // Business Identifier for observation
|
||||
private String status;// @NotNull // registered | preliminary | final | amended +
|
||||
|
@ -139,7 +140,7 @@ public class TestProfile extends PEGeneratedBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Save this profile class into an existing resource (overwriting enything that
|
||||
* Save this profile class into an existing resource (overwriting anything that
|
||||
* exists in the profile)
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
|||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager.FilesystemPackageCacheMode;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.npm.ToolsVersion;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
@ -33,19 +34,8 @@ public class CDARoundTripTests {
|
|||
context = TestingUtilities.getWorkerContext(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1"));
|
||||
fp = new FHIRPathEngine(context);
|
||||
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "any.xml"), "any.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ii.xml"), "ii.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cd.xml"), "cd.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ce.xml"), "ce.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ed.xml"), "ed.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "st.xml"), "st.xml", null);
|
||||
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cda.xml"), "cda.xml", null);
|
||||
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
|
||||
if (!sd.hasSnapshot()) {
|
||||
// System.out.println("generate snapshot for " + sd.getUrl());
|
||||
new ContextUtilities(context).generateSnapshot(sd);
|
||||
}
|
||||
}
|
||||
NpmPackage npm = new FilesystemPackageCacheManager(true).loadPackage("hl7.cda.uv.core");
|
||||
context.loadFromPackage(npm, null);
|
||||
}
|
||||
|
||||
// old-test
|
||||
|
@ -191,16 +181,16 @@ public class CDARoundTripTests {
|
|||
// }
|
||||
|
||||
public void assertsExample(Element cdaExample) {
|
||||
Assertions.assertEquals("2.16.840.1.113883.3.27.1776", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.templateId.root")));
|
||||
Assertions.assertEquals("SoEN", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.displayName")));
|
||||
Assertions.assertEquals("SoEN2", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.sdtcDisplayName")));
|
||||
Assertions.assertEquals("c266", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.id.extension")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.19.4", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.id.root")));
|
||||
Assertions.assertEquals("X-34133-9", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.code")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.6.1", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.codeSystem")));
|
||||
Assertions.assertEquals("LOINC", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.codeSystemName")));
|
||||
Assertions.assertEquals("Episode Note", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.title.dataString")));
|
||||
}
|
||||
Assertions.assertEquals("2.16.840.1.113883.3.27.1776", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.templateId.root")));
|
||||
Assertions.assertEquals("SoEN", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.displayName")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.1.2.3.4.5.6", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.sdtcValueSet")));
|
||||
Assertions.assertEquals("c266", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.id.extension")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.19.4", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.id.root")));
|
||||
Assertions.assertEquals("X-34133-9", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.code")));
|
||||
Assertions.assertEquals("2.16.840.1.113883.6.1", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.codeSystem")));
|
||||
Assertions.assertEquals("LOINC", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.code.codeSystemName")));
|
||||
Assertions.assertEquals("Episode Note", fp.evaluateToString(null, cdaExample, cdaExample, cdaExample, fp.parse("ClinicalDocument.title.dataString")));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
|
|
|
@ -1006,6 +1006,10 @@ public class I18nConstants {
|
|||
public static final String FHIRPATH_CHOICE_NO_TYPE_SPECIFIER = "FHIRPATH_CHOICE_NO_TYPE_SPECIFIER";
|
||||
public static final String FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER = "FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER";
|
||||
public static final String FHIRPATH_NOT_A_COLLECTION = "FHIRPATH_NOT_A_COLLECTION";
|
||||
public static final String TERMINOLOGY_TX_UNKNOWN_OID = "TERMINOLOGY_TX_UNKNOWN_OID";
|
||||
public static final String XSI_TYPE_WRONG = "XSI_TYPE_WRONG";
|
||||
public static final String XSI_TYPE_UNNECESSARY = "XSI_TYPE_UNNECESSARY";
|
||||
public static final String TERMINOLOGY_TX_OID_MULTIPLE_MATCHES = "TERMINOLOGY_TX_OID_MULTIPLE_MATCHES";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ public class JsonObject extends JsonElement {
|
|||
}
|
||||
|
||||
public JsonObject add(String name, JsonElement value) throws JsonException {
|
||||
check(name != null, "Name is null");
|
||||
check(value != null, "Value is null");
|
||||
check(name != null, "Json Property Name is null");
|
||||
check(value != null, "Json Property Value is null");
|
||||
if (get(name) != null) {
|
||||
check(false, "Name '"+name+"' already exists (value = "+get(name).toString()+")");
|
||||
}
|
||||
|
|
|
@ -207,6 +207,10 @@ public class NpmPackage {
|
|||
return folderName;
|
||||
}
|
||||
|
||||
public String getFolderPath() {
|
||||
return folder == null ? null : folder.getAbsolutePath();
|
||||
}
|
||||
|
||||
public boolean readIndex(JsonObject index, Map<String, List<String>> typeMap) {
|
||||
if (!index.has("index-version") || (index.asInteger("index-version") != NpmPackageIndexBuilder.CURRENT_INDEX_VERSION)) {
|
||||
return false;
|
||||
|
@ -228,13 +232,13 @@ public class NpmPackage {
|
|||
List<String> res = new ArrayList<>();
|
||||
if (folder != null) {
|
||||
for (File f : folder.listFiles()) {
|
||||
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db")) {
|
||||
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) {
|
||||
res.add(f.getName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String s : content.keySet()) {
|
||||
if (!Utilities.existsInList(s, "package.json", ".index.json", ".index.db")) {
|
||||
if (!Utilities.existsInList(s, "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) {
|
||||
res.add(s);
|
||||
}
|
||||
}
|
||||
|
@ -311,6 +315,20 @@ public class NpmPackage {
|
|||
}
|
||||
}
|
||||
}
|
||||
public JsonObject oidIndex() throws IOException {
|
||||
if (folder == null) {
|
||||
return null;
|
||||
} else {
|
||||
File ij = new File(fn(".oids.json"));
|
||||
if (ij.exists()) {
|
||||
return JsonParser.parseObject(ij);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String path;
|
||||
|
@ -597,10 +615,11 @@ public class NpmPackage {
|
|||
JsonObject index = folder.index();
|
||||
if (index == null || index.forceArray("files").size() == 0) {
|
||||
indexFolder(desc, folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException {
|
||||
List<String> remove = new ArrayList<>();
|
||||
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
||||
|
@ -675,9 +694,17 @@ public class NpmPackage {
|
|||
public List<String> list(String folder) throws IOException {
|
||||
List<String> res = new ArrayList<String>();
|
||||
if (folders.containsKey(folder)) {
|
||||
res.addAll(folders.get(folder).listFiles());
|
||||
for (String s : folders.get(folder).listFiles()) {
|
||||
if (!s.startsWith(".")) {
|
||||
res.add(s);
|
||||
}
|
||||
}
|
||||
} else if (folders.containsKey(Utilities.path("package", folder))) {
|
||||
res.addAll(folders.get(Utilities.path("package", folder)).listFiles());
|
||||
for (String s : folders.get(Utilities.path("package", folder)).listFiles()) {
|
||||
if (!s.startsWith(".")) {
|
||||
res.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,11 @@ import java.sql.DriverManager;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
|
@ -38,7 +41,6 @@ public class NpmPackageIndexBuilder {
|
|||
files = new JsonArray();
|
||||
index.add("files", files);
|
||||
|
||||
|
||||
dbFilename = filename;
|
||||
if (filename != null) {
|
||||
try {
|
||||
|
@ -109,6 +111,7 @@ public class NpmPackageIndexBuilder {
|
|||
if (json.hasPrimitive("derivation")) {
|
||||
fi.add("derivation", json.asString("derivation"));
|
||||
}
|
||||
|
||||
if (psql != null) {
|
||||
psql.setString(1, name); // FileName);
|
||||
psql.setString(2, json.asString("resourceType")); // ResourceType");
|
||||
|
@ -133,7 +136,7 @@ public class NpmPackageIndexBuilder {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public String build() {
|
||||
try {
|
||||
if (conn != null) {
|
||||
|
@ -215,4 +218,5 @@ public class NpmPackageIndexBuilder {
|
|||
return dbFilename;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -501,7 +501,6 @@ MEASURE_MR_GRP_MISSING_BY_CODE = The MeasureReport does not include a group for
|
|||
MEASURE_MR_GRP_NO_USABLE_CODE = None of the codes provided are usable for comparison - need both system and code on at least one code
|
||||
MEASURE_MR_GRP_NO_WRONG_CODE = The code provided ({0}) does not match the code specified in the measure report ({1})
|
||||
DUPLICATE_ID = Duplicate id value ''{0}''
|
||||
TERMINOLOGY_TX_SYSTEM_NO_CODE = A code with no system has no defined meaning. A system should be provided
|
||||
MEASURE_MR_GRP_POP_NO_CODE = Group should have a code that matches the group population definition in the measure
|
||||
MEASURE_MR_GRP_POP_UNK_CODE = The code for this group population has no match in the measure definition
|
||||
MEASURE_MR_GRPST_POP_UNK_CODE = The code for this group stratifier has no match in the measure definition
|
||||
|
@ -1063,4 +1062,8 @@ LOGICAL_MODEL_QNAME_MISMATCH = The QName ''{0}'' does not match the expected QNa
|
|||
FHIRPATH_CHOICE_NO_TYPE_SPECIFIER = The expression ''{0}'' refers to an element that is a choice, but doesn''t have an .ofType() so that SQL view runners can pre-determine the full element name
|
||||
FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER = The expression ''{0}'' refers to an element that is not a choice, but has an .ofType(). SQL view runners are likely to pre-determine an incorrect full element name
|
||||
FHIRPATH_NOT_A_COLLECTION = Found a use of a collection operator on something that is not a collection at ''{0}'' - check that there's no mistakes in the expression syntax
|
||||
|
||||
TERMINOLOGY_TX_UNKNOWN_OID = The OID ''{0}'' is not known
|
||||
TERMINOLOGY_TX_SYSTEM_NO_CODE = A code with no system has no defined meaning, and it cannot be validated. A system should be provided
|
||||
XSI_TYPE_WRONG = The xsi:type value ''{0}'' is wrong (should be ''{1}''). Note that xsi:type is unnecessary at this point
|
||||
XSI_TYPE_UNNECESSARY = xsi:type is unnecessary at this point
|
||||
TERMINOLOGY_TX_OID_MULTIPLE_MATCHES = The OID ''{0}'' matches multiple code systems ({1})
|
||||
|
|
|
@ -93,6 +93,7 @@ import org.hl7.fhir.r5.model.CanonicalResource;
|
|||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.CodeType;
|
||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.ContactPoint;
|
||||
|
@ -1403,7 +1404,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
|
||||
private boolean checkTerminologyCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, StructureDefinition logical) {
|
||||
private boolean checkCDACodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, StructureDefinition logical) {
|
||||
boolean ok = true;
|
||||
if (!noTerminologyChecks && theElementCntext != null && theElementCntext.hasBinding()) {
|
||||
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
||||
|
@ -1419,7 +1420,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
} else {
|
||||
try {
|
||||
CodeableConcept cc = convertToCodeableConcept(element, logical);
|
||||
CodeableConcept cc = new CodeableConcept();
|
||||
ok = convertCDACodeToCodeableConcept(errors, path, element, logical, cc) && ok;
|
||||
if (!cc.hasCoding()) {
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, "No code provided, and a code is required from the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getVersionedUrl()) && ok;
|
||||
|
@ -1638,43 +1640,39 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ok;
|
||||
}
|
||||
|
||||
private CodeableConcept convertToCodeableConcept(Element element, StructureDefinition logical) {
|
||||
CodeableConcept res = new CodeableConcept();
|
||||
for (ElementDefinition ed : logical.getSnapshot().getElement()) {
|
||||
if (Utilities.charCount(ed.getPath(), '.') == 1) {
|
||||
List<String> maps = getMapping("http://hl7.org/fhir/terminology-pattern", logical, ed);
|
||||
for (String m : maps) {
|
||||
String name = tail(ed.getPath());
|
||||
List<Element> 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 = new ContextUtilities(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) {
|
||||
boolean ok = true;
|
||||
cc.setText(element.getNamedChildValue("originalText"));
|
||||
if (element.hasChild("nullFlavor")) {
|
||||
cc.addExtension("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor", new CodeType(element.getNamedChildValue("nullFlavor")));
|
||||
}
|
||||
return res;
|
||||
if (element.hasChild("code") || element.hasChild("codeSystem")) {
|
||||
Coding c = cc.addCoding();
|
||||
|
||||
String oid = element.getNamedChildValue("codeSystem");
|
||||
if (oid != null) {
|
||||
Set<String> urls = context.urlsForOid(true, oid);
|
||||
if (urls.size() != 1) {
|
||||
c.setSystem("urn:oid:"+oid);
|
||||
ok = false;
|
||||
if (urls.size() == 0) {
|
||||
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_UNKNOWN_OID, oid);
|
||||
} else {
|
||||
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_OID_MULTIPLE_MATCHES, oid, CommaSeparatedStringBuilder.join(",", urls));
|
||||
}
|
||||
} else {
|
||||
c.setSystem(urls.iterator().next());
|
||||
}
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
|
||||
}
|
||||
|
||||
c.setCode(element.getNamedChildValue("code"));
|
||||
c.setVersion(element.getNamedChildValue("codeSystemVersion"));
|
||||
c.setDisplay(element.getNamedChildValue("displayName"));
|
||||
}
|
||||
// todo: translations
|
||||
return ok;
|
||||
}
|
||||
|
||||
private Coding convertToCoding(Element element, StructureDefinition logical) {
|
||||
|
@ -1842,6 +1840,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean checkCoding(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack) {
|
||||
String code = element.getNamedChildValue("code");
|
||||
String system = element.getNamedChildValue("system");
|
||||
if (code != null && system == null) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
|
||||
}
|
||||
String version = element.getNamedChildValue("version");
|
||||
String display = element.getNamedChildValue("display");
|
||||
return checkCodedElement(errors, path, element, profile, theElementCntext, inCodeableConcept, checkDisplay, stack, code, system, version, display);
|
||||
|
@ -1852,7 +1853,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
boolean ok = true;
|
||||
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, theSystem == null || isCodeSystemReferenceValid(theSystem), I18nConstants.TERMINOLOGY_TX_SYSTEM_RELATIVE) && ok;
|
||||
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, Utilities.noString(theCode) || !Utilities.noString(theSystem), I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
|
||||
|
||||
if (theSystem != null && theCode != null && !noTerminologyChecks) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, !isValueSet(theSystem), I18nConstants.TERMINOLOGY_TX_SYSTEM_VALUESET2, theSystem) && ok;
|
||||
|
@ -2628,12 +2628,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
boolean dok = ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
|
||||
e.primitiveValue()
|
||||
.matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, "'"+e.primitiveValue()+"' doesn't meet format requirements for dateTime") && ok;
|
||||
dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !hasTime(e.primitiveValue()) || hasTimeZone(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_TZ) && dok;
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("tz-for-time"))) {
|
||||
dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !hasTime(e.primitiveValue()) || hasTimeZone(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_TZ) && dok;
|
||||
}
|
||||
dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && dok;
|
||||
if (dok) {
|
||||
try {
|
||||
DateTimeType dt = new DateTimeType(e.primitiveValue());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, ex.getMessage());
|
||||
dok = false;
|
||||
|
@ -2658,7 +2662,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (dok) {
|
||||
try {
|
||||
DateType dt = new DateType(e.primitiveValue());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATE_VALID, ex.getMessage());
|
||||
dok = false;
|
||||
|
@ -2753,7 +2759,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (dok) {
|
||||
try {
|
||||
InstantType dt = new InstantType(e.primitiveValue());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INSTANT_VALID, ex.getMessage());
|
||||
dok = false;
|
||||
|
@ -2837,6 +2845,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean isCoreDefinition(StructureDefinition profile) {
|
||||
return profile.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/") && profile.getKind() != StructureDefinitionKind.LOGICAL;
|
||||
}
|
||||
|
||||
private String getRegexFromType(String fhirType) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(fhirType);
|
||||
if (sd != null) {
|
||||
|
@ -5969,7 +5981,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
String thisExtension = null;
|
||||
boolean checkDisplay = true;
|
||||
|
||||
SpecialElement special = ei.getElement().getSpecial();
|
||||
// SpecialElement special = ei.getElement().getSpecial();
|
||||
// this used to say
|
||||
// if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.BUNDLE_ISSUES || special == SpecialElement.PARAMETER) {
|
||||
// ok = checkInvariants(valContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, ei.getElement(), ei.getElement(), localStack, false) && ok;
|
||||
|
@ -6030,13 +6042,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// (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<String> txtype = getMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep());
|
||||
if (txtype.contains("CodeableConcept")) {
|
||||
ok = checkTerminologyCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
|
||||
thisIsCodeableConcept = true;
|
||||
} else if (txtype.contains("Coding")) {
|
||||
ok = checkTerminologyCoding(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack, defn) && ok;
|
||||
if (defn != null && defn.hasExtension(ToolingExtensions.EXT_BINDING_STYLE)) {
|
||||
String style = ToolingExtensions.readStringExtension(defn, ToolingExtensions.EXT_BINDING_STYLE);
|
||||
if ("CDA".equals(style)) {
|
||||
if (cdaTypeIs(defn, "CS")) {
|
||||
ok = checkCDACodeSimple(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
|
||||
} else if (cdaTypeIs(defn, "CV") || cdaTypeIs(defn, "PQ")) {
|
||||
ok = checkCDACoding(errors, ei.getPath(), cdaTypeIs(defn, "PQ"), ei.getElement(), profile, checkDefn, stack, defn, inCodeableConcept, checkDisplayInContext) && ok;
|
||||
} else if (cdaTypeIs(defn, "CD") || cdaTypeIs(defn, "CE")) {
|
||||
ok = checkCDACodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
|
||||
thisIsCodeableConcept = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6141,6 +6157,46 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean cdaTypeIs(StructureDefinition defn, String type) {
|
||||
return ("http://hl7.org/cda/stds/core/StructureDefinition/"+type).equals(defn.getUrl());
|
||||
}
|
||||
|
||||
private boolean checkCDACoding(List<ValidationMessage> errors, String path, boolean isPQ, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn, boolean inCodeableConcept, boolean checkDisplay) {
|
||||
boolean ok = true;
|
||||
String system = null;
|
||||
String code = element.getNamedChildValue(isPQ ? "unit" : "code");
|
||||
String oid = element.getNamedChildValue("codeSystem");
|
||||
if (oid != null) {
|
||||
Set<String> urls = context.urlsForOid(true, oid);
|
||||
if (urls.size() != 1) {
|
||||
system = "urn:oid:"+oid;
|
||||
ok = false;
|
||||
|
||||
if (urls.size() == 0) {
|
||||
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_UNKNOWN_OID, oid);
|
||||
} else {
|
||||
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_OID_MULTIPLE_MATCHES, oid, CommaSeparatedStringBuilder.join(",", urls));
|
||||
}
|
||||
} else {
|
||||
system = urls.iterator().next();
|
||||
}
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, code == null, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
|
||||
}
|
||||
|
||||
String version = element.getNamedChildValue("codeSystemVersion");
|
||||
String display = element.getNamedChildValue("displayName");
|
||||
return checkCodedElement(errors, path, element, profile, checkDefn, inCodeableConcept, checkDisplay, stack, code, system, version, display) && ok;
|
||||
}
|
||||
|
||||
private boolean checkCDACodeSimple(ValidationContext valContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn) {
|
||||
if (element.hasChild("code")) {
|
||||
return checkPrimitiveBinding(valContext, errors, path, "code", checkDefn, element.getNamedChild("code"), profile, stack);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAbstractType(String type) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(type);
|
||||
return sd != null && sd.getAbstract();
|
||||
|
|
|
@ -1407,6 +1407,45 @@ v: {
|
|||
"code" : "CHE",
|
||||
"system" : "urn:iso:std:iso:3166",
|
||||
"version" : "2018",
|
||||
"issues" : {
|
||||
"resourceType" : "OperationOutcome"
|
||||
}
|
||||
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"code" : "en-US"
|
||||
}, "url": "http://terminology.hl7.org/ValueSet/v3-HumanLanguage", "version": "2.0.0", "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"true", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
|
||||
}]
|
||||
}}####
|
||||
v: {
|
||||
"severity" : "error",
|
||||
"error" : "The CodeSystem http://terminology.hl7.org/CodeSystem/ietf3066 is unknown; Unable to check whether the code is in the value set http://terminology.hl7.org/ValueSet/v3-HumanLanguage|2.0.0 (from Tx-Server)",
|
||||
"class" : "CODESYSTEM_UNSUPPORTED",
|
||||
"unknown-systems" : "http://terminology.hl7.org/CodeSystem/ietf3066",
|
||||
"issues" : {
|
||||
"resourceType" : "OperationOutcome"
|
||||
}
|
||||
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"code" : "PRN"
|
||||
}, "valueSet" :null, "langs":"en", "useServer":"true", "useClient":"false", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
|
||||
}]
|
||||
}}####
|
||||
v: {
|
||||
"severity" : "error",
|
||||
"error" : "The CodeSystem is unknown (from Tx-Server)",
|
||||
"class" : "UNKNOWN",
|
||||
"unknown-systems" : "",
|
||||
"issues" : {
|
||||
"resourceType" : "OperationOutcome"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"system" : "urn:oid:2.16.840.1.113883.5.10588",
|
||||
"code" : "GIM",
|
||||
"display" : "General internal medicine clinic"
|
||||
}, "valueSet" :null, "langs":"en", "useServer":"true", "useClient":"false", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
|
||||
}]
|
||||
}}####
|
||||
v: {
|
||||
"severity" : "error",
|
||||
"error" : "The CodeSystem urn:oid:2.16.840.1.113883.5.10588 is unknown (from Tx-Server)",
|
||||
"class" : "CODESYSTEM_UNSUPPORTED",
|
||||
"unknown-systems" : "urn:oid:2.16.840.1.113883.5.10588",
|
||||
"issues" : {
|
||||
"resourceType" : "OperationOutcome"
|
||||
}
|
||||
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
2
pom.xml
2
pom.xml
|
@ -20,7 +20,7 @@
|
|||
<properties>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.4.9</validator_test_case_version>
|
||||
<validator_test_case_version>1.4.10-SNAPSHOT</validator_test_case_version>
|
||||
<jackson_version>2.15.2</jackson_version>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
|
Loading…
Reference in New Issue