Merge pull request #1460 from hapifhir/2023-10-gg-choice-groups

2023 10 gg choice groups
This commit is contained in:
Grahame Grieve 2023-10-13 09:31:02 +08:00 committed by GitHub
commit e2b3e1557f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 3557 additions and 457 deletions

View File

@ -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);");

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -1034,5 +1034,6 @@ public interface IWorkerContext {
public boolean isForPublication();
public void setForPublication(boolean value);
public Set<String> urlsForOid(boolean codeSystem, String oid);
}

View File

@ -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();
}
}
}

View File

@ -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())+"/";
}
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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);");

View File

@ -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)) {

View File

@ -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

View File

@ -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)
*
*/

View File

@ -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
/**

View File

@ -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";
}

View File

@ -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()+")");
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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})

View File

@ -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();

View File

@ -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"

View File

@ -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"
}
}
-------------------------------------------------------------------------------------

View File

@ -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>