Merge branch 'master' of https://github.com/hapifhir/org.hl7.fhir.core into ExampleScenarioRendering
This commit is contained in:
commit
820a945807
|
@ -0,0 +1,49 @@
|
|||
#!/bin/bash
|
||||
IFS=$'\n'
|
||||
|
||||
readarray -t whitelist < ./.github/workflows/license-check/license-whitelist.txt
|
||||
readarray -t specialcases < <( grep -vE "^#" ./.github/workflows/license-check/license-special-cases.txt )
|
||||
|
||||
exitStatus=0
|
||||
|
||||
for specialcase in "${specialcases[@]}"
|
||||
do
|
||||
echo "Special case: " "$specialcase"
|
||||
done
|
||||
|
||||
readarray -t thirdparty < <( tail -n +3 ./target/generated-sources/license/THIRD-PARTY.txt )
|
||||
for thirdpartyentry in "${thirdparty[@]}"
|
||||
do
|
||||
allLicensesValid=true
|
||||
# Remove leading spaces
|
||||
thirdpartyentry="${thirdpartyentry#"${thirdpartyentry%%[![:space:]]*}"}"
|
||||
echo "Evaluating Dependency: " "$thirdpartyentry"
|
||||
if [[ $(echo "${specialcases[@]}" | fgrep -w $thirdpartyentry) ]]
|
||||
then
|
||||
echo " Ignoring: " "$thirdpartyentry"
|
||||
else
|
||||
licenses=($(echo $thirdpartyentry | awk -vRS=")" -vFS="(" '{print $2}'))
|
||||
for (( i=0; i < ${#licenses[@]} - 1 ; i++ ))
|
||||
do
|
||||
#echo ${licenses[i]}
|
||||
licenseToCheck=${licenses[i]}
|
||||
if [[ $(echo "${whitelist[@]}" | fgrep -w $licenseToCheck) ]]
|
||||
then
|
||||
#do nothing bsh no-op
|
||||
:
|
||||
else
|
||||
echo " Unknown license found: " $licenseToCheck
|
||||
allLicensesValid=false
|
||||
exitStatus=1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if $allLicensesValid
|
||||
then
|
||||
echo " All licenses OK"
|
||||
else
|
||||
echo " Possible license incompatibilities found"
|
||||
fi
|
||||
done
|
||||
|
||||
exit $exitStatus
|
|
@ -0,0 +1,3 @@
|
|||
(Unknown license) javaparser (com.google.code.javaparser:javaparser:1.0.11 - http://code.google.com/p/javaparser/)
|
||||
# IGNORE ME
|
||||
(Apache Software License 2.0) HAPI FHIR - Validation Resources (FHIR R4) (ca.uhn.hapi.fhir:hapi-fhir-validation-resources-r4:6.4.1 - https://hapifhir.io/hapi-deployable-pom/hapi-fhir-validation-resources-r4)
|
|
@ -0,0 +1,25 @@
|
|||
The Apache Software License, Version 2.0
|
||||
Apache Software License, version 1.1
|
||||
Apache Software License 2.0
|
||||
The Apache License, Version 2.0
|
||||
The Apache Software License, Version 2.0
|
||||
MIT License
|
||||
The MIT License
|
||||
Apache Software License, version 1.1
|
||||
Apache 2
|
||||
Apache 2.0
|
||||
Apache License 2.0
|
||||
Eclipse Public License v2.0
|
||||
BSD licence
|
||||
The BSD License
|
||||
BSD-Style License
|
||||
BSD License 3
|
||||
New BSD License
|
||||
BSD 3 Clause
|
||||
The JSON License
|
||||
Eclipse Public License - v 1.0
|
||||
Eclipse Public License v. 2.0
|
||||
Eclipse Distribution License v. 1.0
|
||||
Eclipse Distribution License - v 1.0
|
||||
Unicode/ICU License
|
||||
BSD 2-Clause License
|
|
@ -0,0 +1,30 @@
|
|||
# This is a basic workflow that is manually triggered
|
||||
|
||||
name: License Check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "greet"
|
||||
check:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Collect module licenses
|
||||
run: mvn clean install -DskipTests
|
||||
- name: Collect module licenses
|
||||
run: mvn license:add-third-party
|
||||
- name: Aggregate licenses
|
||||
run: mvn license:aggregate-add-third-party
|
||||
- name: Set script permissions
|
||||
run: chmod u+x .github/workflows/license-check/license-check.sh
|
||||
- name: Run script
|
||||
run: .github/workflows/license-check/license-check.sh
|
||||
continue-on-error: true
|
|
@ -1,9 +1,7 @@
|
|||
## Validator Changes
|
||||
|
||||
* Fix invalid integer detection
|
||||
* Improved invariant checking
|
||||
* no changes
|
||||
|
||||
## Other code changes
|
||||
|
||||
* Update obligation handling code for split definitions
|
||||
* Update ICF importer to handle grouping levels
|
||||
* no changes
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
package org.hl7.fhir.convertors.misc;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Date;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.BooleanType;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.CodeType;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.PropertyType;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
||||
import org.hl7.fhir.utilities.CSVReader;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class CPTImporter {
|
||||
|
||||
public static void main(String[] args) throws FHIRException, FileNotFoundException, IOException, ClassNotFoundException, SQLException {
|
||||
new CPTImporter().doImport(args[0], args[1], args[2]);
|
||||
|
||||
}
|
||||
|
||||
private Connection con;
|
||||
|
||||
private void doImport(String src, String version, String dst) throws FHIRException, FileNotFoundException, IOException, ClassNotFoundException, SQLException {
|
||||
|
||||
CodeSystem cs = new CodeSystem();
|
||||
cs.setId("cpt");
|
||||
cs.setUrl("http://www.ama-assn.org/go/cpt");
|
||||
cs.setVersion(version);
|
||||
cs.setName("AmaCPT");
|
||||
cs.setTitle("AMA CPT");
|
||||
cs.setStatus(PublicationStatus.ACTIVE);
|
||||
cs.setDate(new Date());
|
||||
cs.setContent(CodeSystemContentMode.COMPLETE);
|
||||
cs.setCompositional(true);
|
||||
cs.setPublisher("AMA");
|
||||
cs.setValueSet("http://hl7.org/fhir/ValueSet/cpt-all");
|
||||
cs.setCopyright("CPT © Copyright 2019 American Medical Association. All rights reserved. AMA and CPT are registered trademarks of the American Medical Association.");
|
||||
cs.addProperty().setCode("modifier").setDescription("Whether code is a modifier code").setType(PropertyType.BOOLEAN);
|
||||
cs.addProperty().setCode("modified").setDescription("Whether code has been modified (all base codes are not modified)").setType(PropertyType.BOOLEAN);
|
||||
cs.addProperty().setCode("kind").setDescription("Kind of Code (see metadata)").setType(PropertyType.CODE);
|
||||
|
||||
defineMetadata(cs);
|
||||
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "LONGULT.txt"), false, null, null));
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "LONGUT.txt"), false, "upper", null));
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "MEDU.txt"), false, "med", null));
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "SHORTU.txt"), false, "short", null));
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "ConsumerDescriptor.txt"), true, "consumer", null));
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "ClinicianDescriptor.txt"), true, "clinician", null));
|
||||
System.out.println(readCodes(cs, Utilities.path(src, "OrthopoxvirusCodes.txt"), false, null, "orthopod"));
|
||||
|
||||
System.out.println(processModifiers(cs, Utilities.path(src, "modifiers.csv")));
|
||||
|
||||
System.out.println("-------------------");
|
||||
System.out.println(cs.getConcept().size());
|
||||
int c = 0;
|
||||
int k = 0;
|
||||
for (ConceptDefinitionComponent cc: cs.getConcept()) {
|
||||
c = Integer.max(c, cc.getProperty().size());
|
||||
if (cc.getProperty().size() > 3) {
|
||||
k++;
|
||||
}
|
||||
}
|
||||
System.out.println(c);
|
||||
System.out.println(k);
|
||||
|
||||
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(dst), cs);
|
||||
|
||||
connect(Utilities.changeFileExt(dst, ".db"));
|
||||
|
||||
Statement stmt = con.createStatement();
|
||||
stmt.execute("insert into Information (name, value) values ('version', "+cs.getVersion()+")");
|
||||
for (ConceptDefinitionComponent cc: cs.getConcept()) {
|
||||
if (!cc.getCode().startsWith("metadata")) {
|
||||
stmt.execute("insert into Concepts (code, modifier) values ('"+cc.getCode()+"', "+isModifier(cc)+")");
|
||||
int i = 0;
|
||||
if (cc.hasDisplay()) {
|
||||
stmt.execute("insert into Designations (code, type, sequence, value) values ('"+cc.getCode()+"', 0, 0, '"+Utilities.escapeSql(cc.getDisplay())+"')");
|
||||
i++;
|
||||
}
|
||||
for (ConceptDefinitionDesignationComponent d : cc.getDesignation()) {
|
||||
stmt.execute("insert into Designations (code, type, sequence, value) values ('"+cc.getCode()+"', '"+d.getUse().getCode()+"', "+i+", '"+Utilities.escapeSql(d.getValue())+"')");
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (ConceptPropertyComponent p : cc.getProperty()) {
|
||||
if (!Utilities.existsInList(p.getCode(), "modified", "modifier")) {
|
||||
stmt.execute("insert into Properties (code, name, sequence, value) values ('"+cc.getCode()+"', '"+p.getCode()+"', "+i+", '"+p.getValue().primitiveValue()+"')");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cs.getConcept().removeIf(cc -> !Utilities.existsInList(cc.getCode(), "metadata-kinds", "metadata-designations", "99202", "25"));
|
||||
|
||||
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(dst+"-fragment"), cs);
|
||||
}
|
||||
|
||||
private String isModifier(ConceptDefinitionComponent cc) {
|
||||
for (ConceptPropertyComponent p : cc.getProperty()) {
|
||||
if (p.getCode().equals("modifier")) {
|
||||
return p.getValue().primitiveValue().equals("true") ? "1" : "0";
|
||||
}
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
|
||||
private void connect(String dest) throws SQLException, ClassNotFoundException {
|
||||
// Class.forName("com.mysql.jdbc.Driver");
|
||||
// con = DriverManager.getConnection("jdbc:mysql://localhost:3306/omop?useSSL=false","root",{pwd});
|
||||
new File(dest).delete();
|
||||
con = DriverManager.getConnection("jdbc:sqlite:"+dest);
|
||||
makeMetadataTable();
|
||||
makeConceptsTable();
|
||||
makeDesignationsTable();
|
||||
makePropertiesTable();
|
||||
|
||||
}
|
||||
|
||||
private void makeDesignationsTable() throws SQLException {
|
||||
Statement stmt = con.createStatement();
|
||||
stmt.execute("CREATE TABLE Designations (\r\n"+
|
||||
"`code` varchar(15) NOT NULL,\r\n"+
|
||||
"`type` varchar(15) NOT NULL,\r\n"+
|
||||
"`sequence` int NOT NULL,\r\n"+
|
||||
"`value` text NOT NULL,\r\n"+
|
||||
"PRIMARY KEY (`code`, `type`, `sequence`))\r\n");
|
||||
}
|
||||
|
||||
|
||||
private void makePropertiesTable() throws SQLException {
|
||||
|
||||
Statement stmt = con.createStatement();
|
||||
stmt.execute("CREATE TABLE Properties (\r\n"+
|
||||
"`code` varchar(15) NOT NULL,\r\n"+
|
||||
"`name` varchar(15) NOT NULL,\r\n"+
|
||||
"`sequence` int NOT NULL,\r\n"+
|
||||
"`value` varchar(15) NOT NULL,\r\n"+
|
||||
"PRIMARY KEY (`code`, `name`, `sequence`))\r\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void makeConceptsTable() throws SQLException {
|
||||
|
||||
Statement stmt = con.createStatement();
|
||||
stmt.execute("CREATE TABLE Concepts (\r\n"+
|
||||
"`code` varchar(15) NOT NULL,\r\n"+
|
||||
"`modifier` int DEFAULT NULL,\r\n"+
|
||||
"PRIMARY KEY (`code`))\r\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void makeMetadataTable() throws SQLException {
|
||||
|
||||
Statement stmt = con.createStatement();
|
||||
stmt.execute("CREATE TABLE Information (\r\n"+
|
||||
"`name` varchar(64) NOT NULL,\r\n"+
|
||||
"`value` varchar(64) DEFAULT NULL,\r\n"+
|
||||
"PRIMARY KEY (`name`))\r\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void defineMetadata(CodeSystem cs) {
|
||||
ConceptDefinitionComponent pc = mm(cs.addConcept().setCode("metadata-kinds"));
|
||||
mm(pc.addConcept()).setCode("code").setDisplay("A normal CPT code");
|
||||
mm(pc.addConcept()).setCode("cat-1").setDisplay("CPT Level I Modifiers");
|
||||
mm(pc.addConcept()).setCode("cat-2").setDisplay("A Category II code or modifier");
|
||||
mm(pc.addConcept()).setCode("physical-status").setDisplay("Anesthesia Physical Status Modifiers");
|
||||
mm(pc.addConcept()).setCode("general").setDisplay("A general modifier");
|
||||
mm(pc.addConcept()).setCode("hcpcs").setDisplay("Level II (HCPCS/National) Modifiers");
|
||||
mm(pc.addConcept()).setCode("orthopox").setDisplay("");
|
||||
mm(pc.addConcept()).setCode("metadata").setDisplay("A kind of code or designation");
|
||||
|
||||
ConceptDefinitionComponent dc = mm(cs.addConcept().setCode("metadata-designations"));
|
||||
mm(dc.addConcept()).setCode("upper").setDisplay("Uppercase variant of the display");
|
||||
mm(dc.addConcept()).setCode("med").setDisplay("Medium length variant of the display (all uppercase)");
|
||||
mm(dc.addConcept()).setCode("short").setDisplay("Short length variant of the display (all uppercase)");
|
||||
mm(dc.addConcept()).setCode("consumer").setDisplay("Consumer Friendly representation for the concept");
|
||||
mm(dc.addConcept()).setCode("clinician").setDisplay("Clinician Friendly representation for the concept (can be more than one per concept)");
|
||||
}
|
||||
|
||||
private ConceptDefinitionComponent mm(ConceptDefinitionComponent cc) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("metadata"));
|
||||
return cc;
|
||||
}
|
||||
|
||||
private int processModifiers(CodeSystem cs, String path) throws FHIRException, FileNotFoundException, IOException {
|
||||
CSVReader csv = new CSVReader(new FileInputStream(path));
|
||||
csv.readHeaders();
|
||||
|
||||
int res = 0;
|
||||
while (csv.line()) {
|
||||
String code = csv.cell("Code");
|
||||
String general = csv.cell("General");
|
||||
String physicalStatus = csv.cell("PhysicalStatus");
|
||||
String levelOne = csv.cell("LevelOne");
|
||||
String levelTwo = csv.cell("LevelTwo");
|
||||
String hcpcs = csv.cell("HCPCS");
|
||||
String defn = csv.cell("Definition");
|
||||
|
||||
res = Integer.max(res, defn.length());
|
||||
ConceptDefinitionComponent cc = cs.addConcept().setCode(code);
|
||||
cc.setDisplay(defn);
|
||||
cc.addProperty().setCode("modified").setValue(new BooleanType(false));
|
||||
cc.addProperty().setCode("modifier").setValue(new BooleanType(true));
|
||||
if ("1".equals(general)) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("general"));
|
||||
}
|
||||
if ("1".equals(physicalStatus)) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("physical-status"));
|
||||
}
|
||||
if ("1".equals(levelOne)) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("cat-1"));
|
||||
}
|
||||
if ("1".equals(levelTwo)) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("cat-2"));
|
||||
}
|
||||
if ("1".equals(hcpcs)) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("hcpcs"));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private int readCodes(CodeSystem cs, String path, boolean hasConceptId, String use, String type) throws IOException {
|
||||
int res = 0;
|
||||
FileInputStream inputStream = null;
|
||||
Scanner sc = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(path);
|
||||
sc = new Scanner(inputStream, "UTF-8");
|
||||
while (sc.hasNextLine()) {
|
||||
String line = sc.nextLine();
|
||||
if (hasConceptId) {
|
||||
line = line.substring(7).trim();
|
||||
}
|
||||
String code = line.substring(0, 5);
|
||||
String desc = line.substring(6);
|
||||
if (desc.contains("\t")) {
|
||||
desc = desc.substring(desc.indexOf("\t")+1);
|
||||
}
|
||||
res = Integer.max(res, desc.length());
|
||||
ConceptDefinitionComponent cc = CodeSystemUtilities.getCode(cs, code);
|
||||
if (cc == null) {
|
||||
cc = cs.addConcept().setCode(code);
|
||||
cc.addProperty().setCode("modifier").setValue(new BooleanType(false));
|
||||
cc.addProperty().setCode("modified").setValue(new BooleanType(false));
|
||||
if (type == null) {
|
||||
if (Utilities.isInteger(code)) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("code"));
|
||||
} else {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType("cat-2"));
|
||||
}
|
||||
} else {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType(type));
|
||||
}
|
||||
} else if (type != null) {
|
||||
cc.addProperty().setCode("kind").setValue(new CodeType(type));
|
||||
}
|
||||
if (use == null) {
|
||||
if (cc.hasDisplay()) {
|
||||
System.err.println("?");
|
||||
}
|
||||
cc.setDisplay(desc);
|
||||
} else {
|
||||
cc.addDesignation().setUse(new Coding("http://www.ama-assn.org/go/cpt", use, null)).setValue(desc);
|
||||
}
|
||||
}
|
||||
// note that Scanner suppresses exceptions
|
||||
if (sc.ioException() != null) {
|
||||
throw sc.ioException();
|
||||
}
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
if (sc != null) {
|
||||
sc.close();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -192,13 +192,17 @@ public class R5ExtensionsLoader {
|
|||
for (CanonicalType t : inc.getValueSet()) {
|
||||
loadValueSet(t.asStringValue(), context, valueSets, codeSystems);
|
||||
}
|
||||
if (inc.hasSystem() && !inc.hasVersion()) {
|
||||
if (codeSystems.containsKey(inc.getSystem())) {
|
||||
CodeSystem cs = codeSystems.get(inc.getSystem()).getResource();
|
||||
inc.setVersion(cs.getVersion());
|
||||
context.cacheResourceFromPackage(cs, cs.getSourcePackage());
|
||||
} else if (!context.hasResource(CodeSystem.class, inc.getSystem()) && codeSystems.containsKey(inc.getSystem())) {
|
||||
CodeSystem cs1 = codeSystems.get(inc.getSystem()).getResource();
|
||||
if (inc.hasSystem()) {
|
||||
if (!inc.hasVersion()) {
|
||||
if (codeSystems.containsKey(inc.getSystem())) {
|
||||
CodeSystem cs = codeSystems.get(inc.getSystem()).getResource();
|
||||
CodeSystem csAlready = context.fetchCodeSystem(inc.getSystem());
|
||||
if (csAlready == null) {
|
||||
context.cacheResourceFromPackage(cs, cs.getSourcePackage());
|
||||
}
|
||||
}
|
||||
} else if (context.fetchResource(CodeSystem.class, inc.getSystem(), inc.getVersion()) == null && codeSystems.containsKey(inc.getSystem()+"|"+inc.getVersion())) {
|
||||
CodeSystem cs1 = codeSystems.get(inc.getSystem()+"|"+inc.getVersion()).getResource();
|
||||
context.cacheResourceFromPackage(cs1, cs1.getSourcePackage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ import org.hl7.fhir.r5.conformance.ElementRedirection;
|
|||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingComponent;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.SlicingRules;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent;
|
||||
|
@ -193,9 +195,16 @@ public class ProfilePathProcessor {
|
|||
|
||||
private void debugProcessPathsIteration(ProfilePathProcessorState cursors, String currentBasePath) {
|
||||
if (profileUtilities.isDebug()) {
|
||||
System.out.println(getDebugIndent() + " - " + currentBasePath + ": base = " + cursors.baseCursor + " (" + profileUtilities.descED(cursors.base.getElement(), cursors.baseCursor) + ") to " + getBaseLimit() + " (" + profileUtilities.descED(cursors.base.getElement(), getBaseLimit()) + "), diff = " + cursors.diffCursor + " (" + profileUtilities.descED(getDifferential().getElement(), cursors.diffCursor) + ") to " + getDiffLimit() + " (" + profileUtilities.descED(getDifferential().getElement(), getDiffLimit()) + ") " +
|
||||
System.out.println(getDebugIndent() + " - " + currentBasePath + ": "+
|
||||
"base = " + cursors.baseCursor + " (" + profileUtilities.descED(cursors.base.getElement(), cursors.baseCursor) + ") to " + getBaseLimit() +" (" + profileUtilities.descED(cursors.base.getElement(), getBaseLimit()) + "), "+
|
||||
"diff = " + cursors.diffCursor + " (" + profileUtilities.descED(getDifferential().getElement(), cursors.diffCursor) + ") to " + getDiffLimit() + " (" + profileUtilities.descED(getDifferential().getElement(), getDiffLimit()) + ") " +
|
||||
"(slicingDone = " + getSlicing().isDone() + ") (diffpath= " + (getDifferential().getElement().size() > cursors.diffCursor ? getDifferential().getElement().get(cursors.diffCursor).getPath() : "n/a") + ")");
|
||||
String path = cursors.diffCursor >=0 && cursors.diffCursor < getDifferential().getElement().size() ? getDifferential().getElement().get(cursors.diffCursor).present() : null;
|
||||
// if (path != null && path.contains(":populationBasis")) {
|
||||
// System.out.println("!");
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void debugProcessPathsEntry(ProfilePathProcessorState cursors) {
|
||||
|
@ -294,7 +303,7 @@ public class ProfilePathProcessor {
|
|||
|
||||
// differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice.
|
||||
if (!diffMatches.get(0).hasSliceName()) {
|
||||
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(),getSourceStructureDefinition(), getDerived());
|
||||
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(),getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)));
|
||||
profileUtilities.removeStatusExtensions(outcome);
|
||||
if (!outcome.hasContentReference() && !outcome.hasType() && outcome.getPath().contains(".")) {
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NOT_DONE_YET));
|
||||
|
@ -354,6 +363,10 @@ public class ProfilePathProcessor {
|
|||
cursors.diffCursor = newDiffLimit + 1;
|
||||
}
|
||||
|
||||
private String diffPath(ElementDefinition ed) {
|
||||
return "StructureDefinition.differential.element["+differential.getElement().indexOf(ed)+"]";
|
||||
}
|
||||
|
||||
private String slicingSummary(ElementDefinitionSlicingComponent s) {
|
||||
return s.toString();
|
||||
}
|
||||
|
@ -635,6 +648,11 @@ public class ProfilePathProcessor {
|
|||
res = outcome;
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
if (diffMatches.get(0).hasSliceName()) {
|
||||
template = currentBase.copy();
|
||||
template = profileUtilities.updateURLs(getUrl(), getWebUrl(), template);
|
||||
template.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), template.getPath(), getRedirector(), getContextPathSource()));
|
||||
|
||||
checkToSeeIfSlicingExists(diffMatches.get(0), template);
|
||||
outcome.setSliceName(diffMatches.get(0).getSliceName());
|
||||
if (!diffMatches.get(0).hasMin() && (diffMatches.size() > 1 || getSlicing().getElementDefinition()== null || getSlicing().getElementDefinition().getSlicing().getRules() != ElementDefinition.SlicingRules.CLOSED) && !currentBase.hasSliceName()) {
|
||||
if (!currentBasePath.endsWith("xtension.value[x]")) { // hack work around for problems with snapshots in official releases
|
||||
|
@ -642,7 +660,7 @@ public class ProfilePathProcessor {
|
|||
}
|
||||
}
|
||||
}
|
||||
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived());
|
||||
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)));
|
||||
profileUtilities.removeStatusExtensions(outcome);
|
||||
// if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it
|
||||
// outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode()));
|
||||
|
@ -743,6 +761,63 @@ public class ProfilePathProcessor {
|
|||
return res;
|
||||
}
|
||||
|
||||
private void checkToSeeIfSlicingExists(ElementDefinition ed, ElementDefinition template) {
|
||||
List<ElementDefinition> ss = result.getElement();
|
||||
int i = ss.size() -1;
|
||||
ElementDefinition m = null;
|
||||
|
||||
while (i >= 0) {
|
||||
ElementDefinition t = ss.get(i);
|
||||
if (pathsMatch(t.getPath(), ed.getPath())) {
|
||||
if (t.hasSlicing() || t.hasSliceName() || t.getPath().endsWith("[x]")) {
|
||||
m = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t.getPath().length() < ed.getPath().length()) {
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
if (m == null) {
|
||||
if (template.getPath().endsWith(".extension")) {
|
||||
template.getSlicing().setRules(SlicingRules.OPEN);
|
||||
template.getSlicing().setOrdered(false);
|
||||
template.getSlicing().addDiscriminator().setType(DiscriminatorType.VALUE).setPath("url");
|
||||
result.getElement().add(template);
|
||||
} else {
|
||||
System.err.println("checkToSeeIfSlicingExists: "+ed.getPath()+":"+ed.getSliceName()+" is not sliced");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean pathsMatch(String path1, String path2) {
|
||||
String[] p1 = path1.split("\\.");
|
||||
String[] p2 = path2.split("\\.");
|
||||
if (p1.length != p2.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < p1.length; i++) {
|
||||
String pp1 = p1[i];
|
||||
String pp2 = p2[i];
|
||||
if (!pp1.equals(pp2)) {
|
||||
if (pp1.endsWith("[x]")) {
|
||||
if (!pp2.startsWith(pp1.substring(0, pp1.length()-3))) {
|
||||
return false;
|
||||
}
|
||||
} else if (pp2.endsWith("[x]")) {
|
||||
if (!pp1.startsWith(pp2.substring(0, pp2.length()-3))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int indexOfFirstNonChild(StructureDefinitionSnapshotComponent base, ElementDefinition currentBase, int i, int baseLimit) {
|
||||
return baseLimit+1;
|
||||
}
|
||||
|
@ -937,7 +1012,7 @@ public class ProfilePathProcessor {
|
|||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) {
|
||||
profileUtilities.updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing());
|
||||
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived()); // if there's no slice, we don't want to update the unsliced description
|
||||
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0))); // if there's no slice, we don't want to update the unsliced description
|
||||
profileUtilities.removeStatusExtensions(outcome);
|
||||
} else if (!diffMatches.get(0).hasSliceName()) {
|
||||
diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called
|
||||
|
@ -1075,7 +1150,7 @@ public class ProfilePathProcessor {
|
|||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived());
|
||||
profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffItem));
|
||||
profileUtilities.removeStatusExtensions(outcome);
|
||||
// --- LM Added this
|
||||
cursors.diffCursor = getDifferential().getElement().indexOf(diffItem) + 1;
|
||||
|
|
|
@ -139,11 +139,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
public class ElementDefinitionCounter {
|
||||
int countMin = 0;
|
||||
int countMax = 0;
|
||||
int index = 0;
|
||||
ElementDefinition focus;
|
||||
Set<String> names = new HashSet<>();
|
||||
|
||||
public ElementDefinitionCounter(ElementDefinition ed) {
|
||||
public ElementDefinitionCounter(ElementDefinition ed, int i) {
|
||||
focus = ed;
|
||||
index = i;
|
||||
}
|
||||
|
||||
public int checkMin() {
|
||||
|
@ -192,6 +194,11 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
public boolean checkMinMax() {
|
||||
return countMin <= countMax;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum MappingMergeModeOption {
|
||||
|
@ -683,11 +690,12 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
|
||||
checkGroupConstraints(derived);
|
||||
if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
|
||||
int i = 0;
|
||||
for (ElementDefinition e : diff.getElement()) {
|
||||
if (!e.hasUserData(UD_GENERATED_IN_SNAPSHOT) && e.getPath().contains(".")) {
|
||||
ElementDefinition existing = getElementInCurrentContext(e.getPath(), derived.getSnapshot().getElement());
|
||||
if (existing != null) {
|
||||
updateFromDefinition(existing, e, profileName, false, url, base, derived);
|
||||
updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]");
|
||||
} else {
|
||||
ElementDefinition outcome = updateURLs(url, webUrl, e.copy());
|
||||
e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome);
|
||||
|
@ -701,6 +709,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -723,6 +732,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
//Check that all differential elements have a corresponding snapshot element
|
||||
int ce = 0;
|
||||
int i = 0;
|
||||
for (ElementDefinition e : diff.getElement()) {
|
||||
if (!e.hasUserData("diff-source"))
|
||||
throw new Error(context.formatMessage(I18nConstants.UNXPECTED_INTERNAL_CONDITION__NO_SOURCE_ON_DIFF_ELEMENT));
|
||||
|
@ -736,15 +746,16 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
b.append(e.hasId() ? "id: "+e.getId() : "path: "+e.getPath());
|
||||
ce++;
|
||||
if (e.hasId()) {
|
||||
String msg = "No match found in the generated snapshot: check that the path and definitions are legal in the differential (including order)";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+e.getId(), msg, ValidationMessage.IssueSeverity.ERROR));
|
||||
String msg = "No match found for "+e.getId()+" in the generated snapshot: check that the path and definitions are legal in the differential (including order)";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.differential.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!Utilities.noString(b.toString())) {
|
||||
String msg = "The profile "+derived.getUrl()+" has "+ce+" "+Utilities.pluralize("element", ce)+" in the differential ("+b.toString()+") that don't have a matching element in the snapshot: check that the path and definitions are legal in the differential (including order)";
|
||||
if (debug) {
|
||||
System.out.println("Error in snapshot generation: "+msg);
|
||||
System.err.println("Error in snapshot generation: "+msg);
|
||||
if (!debug) {
|
||||
System.out.println("Differential: ");
|
||||
for (ElementDefinition ed : derived.getDifferential().getElement())
|
||||
|
@ -789,10 +800,10 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
tn = tn.substring(tn.lastIndexOf("/")+1);
|
||||
}
|
||||
Map<String, ElementDefinitionCounter> slices = new HashMap<>();
|
||||
int i = 0;
|
||||
i = 0;
|
||||
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
|
||||
if (ed.hasSlicing()) {
|
||||
slices.put(ed.getPath(), new ElementDefinitionCounter(ed));
|
||||
slices.put(ed.getPath(), new ElementDefinitionCounter(ed, i));
|
||||
} else {
|
||||
Set<String> toRemove = new HashSet<>();
|
||||
for (String s : slices.keySet()) {
|
||||
|
@ -809,50 +820,57 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
slice.getFocus().setMin(count);
|
||||
} else {
|
||||
String msg = "The slice definition for "+slice.getFocus().getId()+" has a minimum of "+slice.getFocus().getMin()+" but the slices add up to a minimum of "+count;
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+slice.getFocus().getId(), msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true));
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
|
||||
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true));
|
||||
}
|
||||
}
|
||||
count = slice.checkMax();
|
||||
if (count > -1 && repeats) {
|
||||
String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" but the slices add up to a maximum of "+count+". Check that this is what is intended";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+slice.getFocus().getId(), msg, ValidationMessage.IssueSeverity.INFORMATION));
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
|
||||
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.INFORMATION));
|
||||
}
|
||||
if (!slice.checkMinMax()) {
|
||||
String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" which is less than the minimum of "+slice.getFocus().getMin();
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+"#"+slice.getFocus().getId(), msg, ValidationMessage.IssueSeverity.WARNING));
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
|
||||
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.WARNING));
|
||||
}
|
||||
slices.remove(s);
|
||||
}
|
||||
}
|
||||
if (ed.getPath().contains(".") && !ed.getPath().startsWith(tn+".")) {
|
||||
throw new Error("The element "+ed.getId()+" in the profile '"+derived.getVersionedUrl()+" (["+i+"]) doesn't have the right path (should start with "+tn+".");
|
||||
throw new Error("The element "+ed.getId()+" in the profile '"+derived.getVersionedUrl()+" doesn't have the right path (should start with "+tn+".");
|
||||
}
|
||||
if (ed.hasSliceName() && !slices.containsKey(ed.getPath())) {
|
||||
String msg = "The element "+ed.getId()+" (["+i+"]) launches straight into slicing without the slicing being set up properly first";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
|
||||
String msg = "The element "+ed.getId()+" launches straight into slicing without the slicing being set up properly first";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
|
||||
"StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
|
||||
}
|
||||
if (ed.hasSliceName() && slices.containsKey(ed.getPath())) {
|
||||
if (!slices.get(ed.getPath()).count(ed, ed.getSliceName())) {
|
||||
String msg = "Duplicate slice name "+ed.getSliceName()+" on "+ed.getId()+" (["+i+"])";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
|
||||
"StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
// last, check for wrong profiles or target profiles
|
||||
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
|
||||
for (TypeRefComponent t : ed.getType()) {
|
||||
for (UriType u : t.getProfile()) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue(), derived);
|
||||
if (sd == null) {
|
||||
if (xver != null && xver.matchingUrl(u.getValue()) && xver.status(u.getValue()) == XVerExtensionStatus.Valid) {
|
||||
if (makeXVer().matchingUrl(u.getValue()) && xver.status(u.getValue()) == XVerExtensionStatus.Valid) {
|
||||
sd = xver.makeDefinition(u.getValue());
|
||||
}
|
||||
}
|
||||
if (sd == null) {
|
||||
if (messages != null) {
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING));
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
|
||||
"StructureDefinition.snapshot.element["+i+"]", "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING));
|
||||
}
|
||||
} else {
|
||||
String wt = t.getWorkingCode();
|
||||
|
@ -878,6 +896,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// if we had an exception generating the snapshot, make sure we don't leave any half generated snapshot behind
|
||||
|
@ -891,6 +910,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
private XVerExtensionManager makeXVer() {
|
||||
if (xver == null) {
|
||||
xver = new XVerExtensionManager(context);
|
||||
}
|
||||
return xver;
|
||||
}
|
||||
|
||||
private ElementDefinition getElementInCurrentContext(String path, List<ElementDefinition> list) {
|
||||
for (int i = list.size() -1; i >= 0; i--) {
|
||||
ElementDefinition t = list.get(i);
|
||||
|
@ -1358,7 +1384,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
return true;
|
||||
}
|
||||
if (tr.getWorkingCode().equals(t.getCode())) {
|
||||
System.out.println("Type error: use of a simple type \""+t.getCode()+"\" wrongly constraining "+base.getPath());
|
||||
System.err.println("Type error: use of a simple type \""+t.getCode()+"\" wrongly constraining "+base.getPath());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1759,14 +1785,14 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (type.hasProfile()) {
|
||||
sd = context.fetchResource(StructureDefinition.class, type.getProfile().get(0).getValue(), src);
|
||||
if (sd == null) {
|
||||
if (xver != null && xver.matchingUrl(type.getProfile().get(0).getValue()) && xver.status(type.getProfile().get(0).getValue()) == XVerExtensionStatus.Valid) {
|
||||
if (makeXVer().matchingUrl(type.getProfile().get(0).getValue()) && xver.status(type.getProfile().get(0).getValue()) == XVerExtensionStatus.Valid) {
|
||||
sd = xver.makeDefinition(type.getProfile().get(0).getValue());
|
||||
generateSnapshot(context.fetchTypeDefinition("Extension"), sd, sd.getUrl(), webUrl, sd.getName());
|
||||
}
|
||||
}
|
||||
if (sd == null) {
|
||||
if (debug) {
|
||||
System.out.println("Failed to find referenced profile: " + type.getProfile());
|
||||
System.err.println("Failed to find referenced profile: " + type.getProfile());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1774,14 +1800,14 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (sd == null)
|
||||
sd = context.fetchTypeDefinition(type.getWorkingCode());
|
||||
if (sd == null)
|
||||
System.out.println("XX: failed to find profle for type: " + type.getWorkingCode()); // debug GJM
|
||||
System.err.println("XX: failed to find profle for type: " + type.getWorkingCode()); // debug GJM
|
||||
return sd;
|
||||
}
|
||||
|
||||
protected StructureDefinition getProfileForDataType(String type) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(type);
|
||||
if (sd == null)
|
||||
System.out.println("XX: failed to find profle for type: " + type); // debug GJM
|
||||
System.err.println("XX: failed to find profle for type: " + type); // debug GJM
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
@ -2252,7 +2278,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
|
||||
|
||||
protected void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD, StructureDefinition derivedSrc) throws DefinitionException, FHIRException {
|
||||
protected void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD, StructureDefinition derivedSrc, String path) throws DefinitionException, FHIRException {
|
||||
source.setUserData(UD_GENERATED_IN_SNAPSHOT, dest);
|
||||
// we start with a clone of the base profile ('dest') and we copy from the profile ('source')
|
||||
// over the top for anything the source has
|
||||
|
@ -2297,8 +2323,25 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (base.hasSliceName()) {
|
||||
profile = base.getType().size() == 1 && base.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, base.getTypeFirstRep().getProfile().get(0).getValue(), srcSD) : null;
|
||||
}
|
||||
if (profile==null) {
|
||||
profile = source.getType().size() == 1 && source.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, source.getTypeFirstRep().getProfile().get(0).getValue(), derivedSrc) : null;
|
||||
if (profile == null && source.getTypeFirstRep().hasProfile()) {
|
||||
String pu = source.getTypeFirstRep().getProfile().get(0).getValue();
|
||||
profile = context.fetchResource(StructureDefinition.class, pu, derivedSrc);
|
||||
if (profile == null) {
|
||||
if (makeXVer().matchingUrl(pu)) {
|
||||
switch (xver.status(pu)) {
|
||||
case BadVersion:
|
||||
throw new FHIRException("Reference to invalid version in extension url " + pu);
|
||||
case Invalid:
|
||||
throw new FHIRException("Reference to invalid extension " + pu);
|
||||
case Unknown:
|
||||
throw new FHIRException("Reference to unknown extension " + pu);
|
||||
case Valid:
|
||||
profile = xver.makeDefinition(pu);
|
||||
generateSnapshot(context.fetchTypeDefinition("Extension"), profile, profile.getUrl(), context.getSpecUrl(), profile.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (profile != null && !"Extension".equals(profile.getType()) && profile.getKind() != StructureDefinitionKind.RESOURCE && profile.getKind() != StructureDefinitionKind.LOGICAL) {
|
||||
// this is a problem - we're kind of hacking things here. The problem is that we sometimes want the details from the profile to override the
|
||||
// inherited attributes, and sometimes not
|
||||
|
@ -2666,7 +2709,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (!Base.compareDeep(derived.getType(), base.getType(), false)) {
|
||||
if (base.hasType()) {
|
||||
for (TypeRefComponent ts : derived.getType()) {
|
||||
checkTypeDerivation(purl, derivedSrc, base, derived, ts);
|
||||
checkTypeDerivation(purl, derivedSrc, base, derived, ts, path);
|
||||
}
|
||||
}
|
||||
base.getType().clear();
|
||||
|
@ -2792,7 +2835,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
private void checkTypeDerivation(String purl, StructureDefinition srcSD, ElementDefinition base, ElementDefinition derived, TypeRefComponent ts) {
|
||||
private void checkTypeDerivation(String purl, StructureDefinition srcSD, ElementDefinition base, ElementDefinition derived, TypeRefComponent ts, String path) {
|
||||
boolean ok = false;
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
String t = ts.getWorkingCode();
|
||||
|
@ -2814,13 +2857,14 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
}
|
||||
// work around for old badly generated SDs
|
||||
if (DONT_DO_THIS && Utilities.existsInList(tt, "Extension", "uri", "string", "Element")) {
|
||||
matchType = true;
|
||||
}
|
||||
if (DONT_DO_THIS && Utilities.existsInList(tt, "Resource","DomainResource") && pkp.isResource(t)) {
|
||||
matchType = true;
|
||||
}
|
||||
// if (DONT_DO_THIS && Utilities.existsInList(tt, "Extension", "uri", "string", "Element")) {
|
||||
// matchType = true;
|
||||
// }
|
||||
// if (DONT_DO_THIS && Utilities.existsInList(tt, "Resource","DomainResource") && pkp.isResource(t)) {
|
||||
// matchType = true;
|
||||
// }
|
||||
if (matchType) {
|
||||
ts.copyExtensions(td, "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support", "http://hl7.org/fhir/StructureDefinition/elementdefinition-pattern", "http://hl7.org/fhir/StructureDefinition/obligation");
|
||||
if (ts.hasTargetProfile()) {
|
||||
// check that any derived target has a reference chain back to one of the base target profiles
|
||||
for (UriType u : ts.getTargetProfile()) {
|
||||
|
@ -2830,7 +2874,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
||||
if (sd == null) {
|
||||
if (messages != null) {
|
||||
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, purl + "#" + derived.getPath(), "Cannot check whether the target profile " + url + " is valid constraint on the base because it is not known", IssueSeverity.WARNING));
|
||||
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+derived.getPath()+" is valid constraint on the base because it is not known", IssueSeverity.WARNING));
|
||||
}
|
||||
url = null;
|
||||
tgtOk = true; // suppress error message
|
||||
|
@ -2839,9 +2883,9 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
tgtOk = td.hasTargetProfile(url);
|
||||
}
|
||||
}
|
||||
if (tgtOk)
|
||||
if (tgtOk) {
|
||||
ok = true;
|
||||
else {
|
||||
} else {
|
||||
if (messages == null) {
|
||||
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile()));
|
||||
} else {
|
||||
|
|
|
@ -1490,6 +1490,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
String system = null;
|
||||
String code = null;
|
||||
String version = null;
|
||||
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
|
||||
TerminologyServiceErrorClass err = TerminologyServiceErrorClass.UNKNOWN;
|
||||
for (ParametersParameterComponent p : pOut.getParameter()) {
|
||||
if (p.hasValue()) {
|
||||
|
@ -1506,7 +1508,19 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
} else if (p.getName().equals("code")) {
|
||||
code = ((PrimitiveType<?>) p.getValue()).asStringValue();
|
||||
} else if (p.getName().equals("x-caused-by-unknown-system")) {
|
||||
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
|
||||
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
|
||||
} else if (p.getName().equals("warning-withdrawn")) {
|
||||
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
|
||||
iss.getDetails().setText(formatMessage(I18nConstants.MSG_WITHDRAWN, ((PrimitiveType<?>) p.getValue()).asStringValue()));
|
||||
issues.add(iss);
|
||||
} else if (p.getName().equals("warning-deprecated")) {
|
||||
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
|
||||
iss.getDetails().setText(formatMessage(I18nConstants.MSG_DEPRECATED, ((PrimitiveType<?>) p.getValue()).asStringValue()));
|
||||
issues.add(iss);
|
||||
} else if (p.getName().equals("warning-retired")) {
|
||||
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
|
||||
iss.getDetails().setText(formatMessage(I18nConstants.MSG_RETIRED, ((PrimitiveType<?>) p.getValue()).asStringValue()));
|
||||
issues.add(iss);
|
||||
} else if (p.getName().equals("cause")) {
|
||||
try {
|
||||
IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue());
|
||||
|
@ -1524,15 +1538,18 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
}
|
||||
}
|
||||
ValidationResult res = null;
|
||||
if (!ok) {
|
||||
return new ValidationResult(IssueSeverity.ERROR, message+" (from "+tcc.getClient().getId()+")", err, null).setTxLink(txLog.getLastId());
|
||||
res = new ValidationResult(IssueSeverity.ERROR, message+" (from "+tcc.getClient().getId()+")", err, null).setTxLink(txLog.getLastId());
|
||||
} else if (message != null && !message.equals("No Message returned")) {
|
||||
return new ValidationResult(IssueSeverity.WARNING, message+" (from "+tcc.getClient().getId()+")", system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display, null).setTxLink(txLog.getLastId());
|
||||
res = new ValidationResult(IssueSeverity.WARNING, message+" (from "+tcc.getClient().getId()+")", system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display, null).setTxLink(txLog.getLastId());
|
||||
} else if (display != null) {
|
||||
return new ValidationResult(system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display).setTxLink(txLog.getLastId());
|
||||
res = new ValidationResult(system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display).setTxLink(txLog.getLastId());
|
||||
} else {
|
||||
return new ValidationResult(system, version, new ConceptDefinitionComponent().setCode(code), null).setTxLink(txLog.getLastId());
|
||||
res = new ValidationResult(system, version, new ConceptDefinitionComponent().setCode(code), null).setTxLink(txLog.getLastId());
|
||||
}
|
||||
res.setIssues(issues );
|
||||
return res;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -124,7 +124,7 @@ public interface IWorkerContext {
|
|||
private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
private CodeableConcept codeableConcept;
|
||||
private Set<String> unknownSystems;
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValidationResult [definition=" + definition + ", system=" + system + ", severity=" + severity + ", message=" + message + ", errorClass="
|
||||
|
@ -315,6 +315,14 @@ public interface IWorkerContext {
|
|||
}
|
||||
}
|
||||
|
||||
public void setIssues(List<OperationOutcomeIssueComponent> issues) {
|
||||
if (this.issues != null) {
|
||||
issues.addAll(this.issues);
|
||||
}
|
||||
this.issues = issues;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CodingValidationRequest {
|
||||
|
|
|
@ -544,8 +544,9 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
if (s.startsWith("version=")) {
|
||||
if (version == null)
|
||||
version = s.substring(8);
|
||||
else if (!version.equals(s.substring(8)))
|
||||
else if (!version.equals(s.substring(8))) {
|
||||
throw new DefinitionException(formatMessage(I18nConstants.VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_, version, s.substring(8)));
|
||||
}
|
||||
}
|
||||
if (s.startsWith("revision="))
|
||||
revision = s.substring(9);
|
||||
|
|
|
@ -695,10 +695,7 @@ public class TerminologyCache {
|
|||
}
|
||||
|
||||
protected String hashJson(String s) {
|
||||
s = StringUtils.remove(s, ' ');
|
||||
s = StringUtils.remove(s, '\n');
|
||||
s = StringUtils.remove(s, '\r');
|
||||
return String.valueOf(s.hashCode());
|
||||
return String.valueOf(s.trim().hashCode());
|
||||
}
|
||||
|
||||
// management
|
||||
|
|
|
@ -498,6 +498,14 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
|
|||
}
|
||||
}
|
||||
|
||||
public void copyNewExtensions(org.hl7.fhir.r5.model.Element src, String... urls) {
|
||||
for (Extension e : src.getExtension()) {
|
||||
if (Utilities.existsInList(e.getUrl(), urls) && !!hasExtension(e.getUrl())) {
|
||||
addExtension(e.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// end addition
|
||||
|
||||
|
|
|
@ -12748,6 +12748,15 @@ If a pattern[x] is declared on a repeating element, the pattern applies to all r
|
|||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public List<String> typeList() {
|
||||
List<String> res = new ArrayList<>();
|
||||
for (TypeRefComponent tr : getType()) {
|
||||
if (tr.hasCode())
|
||||
res.add(tr.getWorkingCode());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public String typeSummaryVB() {
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("|");
|
||||
|
|
|
@ -1753,6 +1753,14 @@ public String toString() {
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasParameterValue(String name, String value) {
|
||||
for (ParametersParameterComponent p : getParameter()) {
|
||||
if (p.getName().equals(name) && p.hasValue() && value.equals(p.getValue().primitiveValue()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasParameter(String name) {
|
||||
|
|
|
@ -2839,12 +2839,24 @@ public class ValueSet extends MetadataResource {
|
|||
, total, offset, parameter, property, contains);
|
||||
}
|
||||
|
||||
public String fhirType() {
|
||||
return "ValueSet.expansion";
|
||||
public boolean hasParameterValue(String name, String value) {
|
||||
for (ValueSetExpansionParameterComponent p : getParameter()) {
|
||||
if (name.equals(p.getName()) && p.hasValue() && value.equals(p.getValue().primitiveValue())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
public void addParameter(String name, DataType value) {
|
||||
getParameter().add(new ValueSetExpansionParameterComponent(name).setValue(value));
|
||||
}
|
||||
|
||||
public String fhirType() {
|
||||
return "ValueSet.expansion";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Block()
|
||||
public static class ValueSetExpansionParameterComponent extends BackboneElement implements IBaseBackboneElement {
|
||||
|
|
|
@ -198,7 +198,6 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
generateContentModeNotices(x, vs.getExpansion(), vs);
|
||||
generateVersionNotice(x, vs.getExpansion(), vs);
|
||||
|
||||
CodeSystem allCS = null;
|
||||
boolean doLevel = false;
|
||||
for (ValueSetExpansionContainsComponent cc : vs.getExpansion().getContains()) {
|
||||
if (cc.hasContains()) {
|
||||
|
@ -206,8 +205,9 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean doInactive = checkDoInactive(vs.getExpansion().getContains());
|
||||
boolean doDefinition = checkDoDefinition(vs.getExpansion().getContains());
|
||||
|
||||
XhtmlNode t = x.table( "codes");
|
||||
XhtmlNode tr = t.tr();
|
||||
if (doLevel)
|
||||
|
@ -221,6 +221,9 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
scanForDesignations(c, langs, designations);
|
||||
}
|
||||
scanForProperties(vs.getExpansion(), langs, properties);
|
||||
if (doInactive) {
|
||||
tr.td().b().tx("Inactive");
|
||||
}
|
||||
if (doDefinition) {
|
||||
tr.td().b().tx("Definition");
|
||||
doDesignations = false;
|
||||
|
@ -250,7 +253,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
|
||||
addMapHeaders(tr, maps);
|
||||
for (ValueSetExpansionContainsComponent c : vs.getExpansion().getContains()) {
|
||||
addExpansionRowToTable(t, vs, c, 1, doLevel, true, doDefinition, maps, allCS, langs, designations, doDesignations, properties);
|
||||
addExpansionRowToTable(t, vs, c, 1, doLevel, doDefinition, doInactive, maps, langs, designations, doDesignations, properties);
|
||||
}
|
||||
|
||||
// now, build observed languages
|
||||
|
@ -673,6 +676,17 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean checkDoInactive(List<ValueSetExpansionContainsComponent> contains) {
|
||||
for (ValueSetExpansionContainsComponent c : contains) {
|
||||
if (c.hasInactive()) {
|
||||
return true;
|
||||
}
|
||||
if (checkDoInactive(c.getContains()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean allFromOneSystem(ValueSet vs) {
|
||||
if (vs.getExpansion().getContains().isEmpty())
|
||||
|
@ -754,7 +768,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
private void addExpansionRowToTable(XhtmlNode t, ValueSet vs, ValueSetExpansionContainsComponent c, int i, boolean doLevel, boolean doSystem, boolean doDefinition, List<UsedConceptMap> maps, CodeSystem allCS, List<String> langs, Map<String, String> designations, boolean doDesignations, Map<String, String> properties) throws FHIRFormatError, DefinitionException, IOException {
|
||||
private void addExpansionRowToTable(XhtmlNode t, ValueSet vs, ValueSetExpansionContainsComponent c, int i, boolean doLevel, boolean doDefinition, boolean doInactive, List<UsedConceptMap> maps, List<String> langs, Map<String, String> designations, boolean doDesignations, Map<String, String> properties) throws FHIRFormatError, DefinitionException, IOException {
|
||||
XhtmlNode tr = t.tr();
|
||||
if (ValueSetUtilities.isDeprecated(vs, c)) {
|
||||
tr.setAttribute("style", "background-color: #ffeeee");
|
||||
|
@ -772,19 +786,21 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
String s = Utilities.padLeft("", '\u00A0', i*2);
|
||||
td.attribute("style", "white-space:nowrap").addText(s);
|
||||
addCodeToTable(c.getAbstract(), c.getSystem(), c.getCode(), c.getDisplay(), td);
|
||||
if (doSystem) {
|
||||
td = tr.td();
|
||||
td.addText(c.getSystem());
|
||||
}
|
||||
td = tr.td();
|
||||
td.addText(c.getSystem());
|
||||
td = tr.td();
|
||||
if (c.hasDisplayElement())
|
||||
td.addText(c.getDisplay());
|
||||
|
||||
if (doDefinition) {
|
||||
CodeSystem cs = allCS;
|
||||
if (cs == null)
|
||||
cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
|
||||
if (doInactive) {
|
||||
td = tr.td();
|
||||
if (c.getInactive()) {
|
||||
td.tx("inactive");
|
||||
}
|
||||
}
|
||||
if (doDefinition) {
|
||||
td = tr.td();
|
||||
CodeSystem cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
|
||||
if (cs != null) {
|
||||
String defn = CodeSystemUtilities.getCodeDefinition(cs, c.getCode());
|
||||
addMarkdown(td, defn, cs.getWebPath());
|
||||
|
@ -817,7 +833,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
addLangaugesToRow(c, langs, tr);
|
||||
}
|
||||
for (ValueSetExpansionContainsComponent cc : c.getContains()) {
|
||||
addExpansionRowToTable(t, vs, cc, i+1, doLevel, doSystem, doDefinition, maps, allCS, langs, designations, doDesignations, properties);
|
||||
addExpansionRowToTable(t, vs, cc, i+1, doLevel, doDefinition, doInactive, maps, langs, designations, doDesignations, properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -369,6 +369,10 @@ public class CodeSystemUtilities {
|
|||
if ("inactive".equals(p.getCode()) && p.hasValueBooleanType()) {
|
||||
return p.getValueBooleanType().getValue();
|
||||
}
|
||||
if ("inactive".equals(p.getCode()) && p.hasValueCodeType()) {
|
||||
String code = p.getValueCodeType().primitiveValue();
|
||||
return "true".equals(code);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -124,7 +124,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
|
||||
private static final boolean REPORT_VERSION_ANYWAY = true;
|
||||
|
||||
private IWorkerContext context;
|
||||
private ValueSet focus;
|
||||
private List<String> allErrors = new ArrayList<>();
|
||||
private List<String> requiredSupplements = new ArrayList<>();
|
||||
|
@ -151,9 +150,9 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
|
||||
private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams,
|
||||
boolean isAbstract, boolean inactive, String definition, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp,
|
||||
List<ConceptPropertyComponent> csProps, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList) throws ETooCostly {
|
||||
List<ConceptPropertyComponent> csProps, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp) throws ETooCostly {
|
||||
|
||||
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
|
||||
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp))
|
||||
return null;
|
||||
if (noInactive && inactive) {
|
||||
return null;
|
||||
|
@ -285,10 +284,12 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
return n;
|
||||
}
|
||||
|
||||
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
|
||||
for (ValueSet vse : filters)
|
||||
private boolean filterContainsCode(List<ValueSet> filters, String system, String code, ValueSetExpansionComponent exp) {
|
||||
for (ValueSet vse : filters) {
|
||||
checkCanonical(exp, vse);
|
||||
if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -312,18 +313,18 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc) throws FHIRException, ETooCostly {
|
||||
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
|
||||
focus.checkNoModifiers("Expansion.contains", "expanding");
|
||||
ValueSetExpansionContainsComponent np = null;
|
||||
for (String code : getCodesForConcept(focus, expParams)) {
|
||||
ValueSetExpansionContainsComponent t = addCode(wc, focus.getSystem(), code, focus.getDisplay(), vsSrc.getLanguage(), parent,
|
||||
convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), filters, noInactive, false, vsProps, null, focus.getProperty(), null, focus.getExtension());
|
||||
convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), filters, noInactive, false, vsProps, null, focus.getProperty(), null, focus.getExtension(), exp);
|
||||
if (np == null) {
|
||||
np = t;
|
||||
}
|
||||
}
|
||||
for (ValueSetExpansionContainsComponent c : focus.getContains())
|
||||
addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc);
|
||||
addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc, exp);
|
||||
}
|
||||
|
||||
private List<String> getCodesForConcept(ValueSetExpansionContainsComponent focus, Parameters expParams) {
|
||||
|
@ -349,8 +350,8 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
return list;
|
||||
}
|
||||
|
||||
private void addCodeAndDescendents(WorkingContext wc,CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters,
|
||||
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, List<WorkingContext> otherFilters) throws FHIRException, ETooCostly {
|
||||
private void addCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters,
|
||||
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, List<WorkingContext> otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
|
||||
def.checkNoModifiers("Code in Code System", "expanding");
|
||||
if (exclusion != null) {
|
||||
if (exclusion.getCode().equals(def.getCode()))
|
||||
|
@ -362,19 +363,19 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
boolean dep = CodeSystemUtilities.isDeprecated(cs, def, false);
|
||||
if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) {
|
||||
for (String code : getCodesForConcept(def, expParams)) {
|
||||
ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, def.getDefinition(), filters, noInactive, dep, vsProps, def.getProperty(), null, def.getExtension(), null);
|
||||
ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, def.getDefinition(), filters, noInactive, dep, vsProps, def.getProperty(), null, def.getExtension(), null, exp);
|
||||
if (np == null) {
|
||||
np = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ConceptDefinitionComponent c : def.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters);
|
||||
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters, exp);
|
||||
}
|
||||
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
|
||||
List<ConceptDefinitionComponent> children = (List<ConceptDefinitionComponent>) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK);
|
||||
for (ConceptDefinitionComponent c : children)
|
||||
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters);
|
||||
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +402,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
|
||||
|
||||
|
||||
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc) throws ETooCostly, FHIRException {
|
||||
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws ETooCostly, FHIRException {
|
||||
if (expand != null) {
|
||||
if (expand.getContains().size() > maxExpansionSize)
|
||||
throw failCostly(context.formatMessage(I18nConstants.VALUESET_TOO_COSTLY, vsSrc.getUrl(), ">" + Integer.toString(expand.getContains().size())));
|
||||
|
@ -410,7 +411,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
params.add(p);
|
||||
}
|
||||
|
||||
copyImportContains(expand.getContains(), null, expParams, filters, noInactive, vsProps, vsSrc);
|
||||
copyImportContains(expand.getContains(), null, expParams, filters, noInactive, vsProps, vsSrc, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,8 +451,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
throw fail("not done yet - multiple filters");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void excludeCodes(WorkingContext wc, ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
||||
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
||||
excludeCode(wc, c.getSystem(), c.getCode());
|
||||
|
@ -460,8 +459,9 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
|
||||
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, DataType value) {
|
||||
for (ValueSetExpansionParameterComponent p : params) {
|
||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -503,6 +503,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
||||
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
||||
focus.getExpansion().setIdentifier(Factory.createUUID());
|
||||
checkCanonical(focus.getExpansion(), focus);
|
||||
for (ParametersParameterComponent p : expParams.getParameter()) {
|
||||
if (Utilities.existsInList(p.getName(), "includeDesignations", "excludeNested", "activeOnly", "offset", "count")) {
|
||||
focus.getExpansion().addParameter().setName(p.getName()).setValue(p.getValue());
|
||||
|
@ -642,6 +643,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
throw fail("Unable to find imported value set " + value);
|
||||
}
|
||||
}
|
||||
checkCanonical(exp, vs);
|
||||
if (noInactive) {
|
||||
expParams = expParams.copy();
|
||||
expParams.addParameter("activeOnly", true);
|
||||
|
@ -714,12 +716,12 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
}
|
||||
}
|
||||
|
||||
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc) throws FHIRException, ETooCostly {
|
||||
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
|
||||
for (ValueSetExpansionContainsComponent c : list) {
|
||||
c.checkNoModifiers("Imported Expansion in Code System", "expanding");
|
||||
ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(), c.getExtensionString(ToolingExtensions.EXT_DEFINITION),
|
||||
filter, noInactive, false, vsProps, null, c.getProperty(), null, c.getExtension());
|
||||
copyImportContains(c.getContains(), np, expParams, filter, noInactive, vsProps, vsSrc);
|
||||
filter, noInactive, false, vsProps, null, c.getProperty(), null, c.getExtension(), exp);
|
||||
copyImportContains(c.getContains(), np, expParams, filter, noInactive, vsProps, vsSrc, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -734,9 +736,10 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
if (imports.isEmpty()) // though this is not supposed to be the case
|
||||
return;
|
||||
ValueSet base = imports.get(0);
|
||||
checkCanonical(exp, base);
|
||||
imports.remove(0);
|
||||
base.checkNoModifiers("Imported ValueSet", "expanding");
|
||||
copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base);
|
||||
copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base, exp);
|
||||
} else {
|
||||
CodeSystem cs = context.fetchSupplementedCodeSystem(inc.getSystem());
|
||||
if (ValueSetUtilities.isServerSide(inc.getSystem()) || (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT))) {
|
||||
|
@ -783,7 +786,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
}
|
||||
}
|
||||
for (ValueSetExpansionContainsComponent cc : vs.getExpansion().getContains()) {
|
||||
addCodeAndDescendents(dwc, cc, null, expParams, imports, noInactive, vsProps, vs);
|
||||
addCodeAndDescendents(dwc, cc, null, expParams, imports, noInactive, vsProps, vs, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -795,6 +798,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
else
|
||||
throw failTSE("Unable to find code system " + inc.getSystem().toString());
|
||||
}
|
||||
checkCanonical(exp, cs);
|
||||
cs.checkNoModifiers("Code System", "expanding");
|
||||
if (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)
|
||||
throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete");
|
||||
|
@ -813,7 +817,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
|
||||
// special case - add all the code system
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(dwc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), null);
|
||||
addCodeAndDescendents(dwc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), null, exp);
|
||||
}
|
||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
addFragmentWarning(exp, cs);
|
||||
|
@ -846,7 +850,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
isAbstract = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||
}
|
||||
addCode(dwc, inc.getSystem(), c.getCode(), !Utilities.noString(c.getDisplay()) ? c.getDisplay() : def == null ? null : def.getDisplay(), c.hasDisplay() ? vsSrc.getLanguage() : cs.getLanguage(), null, mergeDesignations(def, convertDesignations(c.getDesignation())),
|
||||
expParams, isAbstract, inactive, def == null ? null : def.getDefinition(), imports, noInactive, false, exp.getProperty(), def != null ? def.getProperty() : null, null, def == null ? null : def.getExtension(), c.getExtension());
|
||||
expParams, isAbstract, inactive, def == null ? null : def.getDefinition(), imports, noInactive, false, exp.getProperty(), def != null ? def.getProperty() : null, null, def == null ? null : def.getExtension(), c.getExtension(), exp);
|
||||
}
|
||||
}
|
||||
if (inc.getFilter().size() > 0) {
|
||||
|
@ -876,14 +880,14 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISNOTA) {
|
||||
// special: all codes in the target code system that are not under the value
|
||||
ConceptDefinitionComponent defEx = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (defEx == null)
|
||||
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
||||
// special: all codes in the target code system under the value
|
||||
|
@ -891,11 +895,11 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
if (def == null)
|
||||
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
|
||||
List<ConceptDefinitionComponent> children = (List<ConceptDefinitionComponent>) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK);
|
||||
for (ConceptDefinitionComponent c : children)
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
|
||||
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||
|
@ -907,18 +911,18 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) {
|
||||
for (String code : getCodesForConcept(def, expParams)) {
|
||||
ValueSetExpansionContainsComponent t = addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
|
||||
def.getDefinition(), imports, noInactive, false, exp.getProperty(), def.getProperty(), null, def.getExtension(), null);
|
||||
def.getDefinition(), imports, noInactive, false, exp.getProperty(), def.getProperty(), null, def.getExtension(), null, exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isDefinedProperty(cs, fc.getProperty())) {
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), noInactive, exp.getProperty(), filters);
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
} else if ("code".equals(fc.getProperty()) && fc.getOp() == FilterOperator.REGEX) {
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new RegexFilter(allErrors, fc.getValue()), noInactive, exp.getProperty(), filters);
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new RegexFilter(allErrors, fc.getValue()), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
} else {
|
||||
throw fail("Filter by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
package org.hl7.fhir.r5.terminologies.utilities;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.model.BooleanType;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.BooleanType;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
|
||||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r5.model.PrimitiveType;
|
||||
import org.hl7.fhir.r5.model.UriType;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.StandardsStatus;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
public class ValueSetProcessBase {
|
||||
|
||||
protected IWorkerContext context;
|
||||
|
||||
public static class AlternateCodesProcessingRules {
|
||||
private boolean all;
|
||||
private List<String> uses = new ArrayList<>();
|
||||
|
@ -77,6 +88,88 @@ public class ValueSetProcessBase {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
protected List<OperationOutcomeIssueComponent> makeIssue(IssueSeverity level, IssueType type, String location, String message) {
|
||||
OperationOutcomeIssueComponent result = new OperationOutcomeIssueComponent();
|
||||
switch (level) {
|
||||
case ERROR:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR);
|
||||
break;
|
||||
case FATAL:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL);
|
||||
break;
|
||||
case INFORMATION:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION);
|
||||
break;
|
||||
case WARNING:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
|
||||
break;
|
||||
}
|
||||
result.setCode(type);
|
||||
result.addLocation(location);
|
||||
result.getDetails().setText(message);
|
||||
ArrayList<OperationOutcomeIssueComponent> list = new ArrayList<>();
|
||||
list.add(result);
|
||||
return list;
|
||||
}
|
||||
|
||||
public void checkCanonical(List<OperationOutcomeIssueComponent> issues, String path, CanonicalResource resource) {
|
||||
if (resource != null) {
|
||||
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
|
||||
if (standardsStatus == StandardsStatus.DEPRECATED) {
|
||||
addToIssues(issues, makeStatusIssue(path, "deprecated", I18nConstants.MSG_DEPRECATED, resource));
|
||||
} else if (standardsStatus == StandardsStatus.WITHDRAWN) {
|
||||
addToIssues(issues, makeStatusIssue(path, "withdrawn", I18nConstants.MSG_WITHDRAWN, resource));
|
||||
} else if (resource.getStatus() == PublicationStatus.RETIRED) {
|
||||
addToIssues(issues, makeStatusIssue(path, "retired", I18nConstants.MSG_RETIRED, resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<OperationOutcomeIssueComponent> makeStatusIssue(String path, String id, String msg, CanonicalResource resource) {
|
||||
List<OperationOutcomeIssueComponent> iss = makeIssue(IssueSeverity.INFORMATION, IssueType.EXPIRED, path, context.formatMessage(msg, resource.getVersionedUrl()));
|
||||
|
||||
// this is a testing hack - see TerminologyServiceTests
|
||||
iss.get(0).setUserData("status-msg-name", "warning-"+id);
|
||||
iss.get(0).setUserData("status-msg-value", new UriType(resource.getVersionedUrl()));
|
||||
|
||||
return iss;
|
||||
}
|
||||
|
||||
private void addToIssues(List<OperationOutcomeIssueComponent> issues, List<OperationOutcomeIssueComponent> toAdd) {
|
||||
for (OperationOutcomeIssueComponent t : toAdd) {
|
||||
boolean found = false;
|
||||
for (OperationOutcomeIssueComponent i : issues) {
|
||||
if (i.getSeverity() == t.getSeverity() && i.getCode() == t.getCode() && i.getDetails().getText().equals(t.getDetails().getText())) { // ignore location
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
issues.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkCanonical(ValueSetExpansionComponent params, CanonicalResource resource) {
|
||||
if (resource != null) {
|
||||
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
|
||||
if (standardsStatus == StandardsStatus.DEPRECATED) {
|
||||
if (!params.hasParameterValue("warning-deprecated", resource.getVersionedUrl())) {
|
||||
params.addParameter("warning-deprecated", new UriType(resource.getVersionedUrl()));
|
||||
}
|
||||
} else if (standardsStatus == StandardsStatus.WITHDRAWN) {
|
||||
if (!params.hasParameterValue("warning-withdrawn", resource.getVersionedUrl())) {
|
||||
params.addParameter("warning-withdrawn", new UriType(resource.getVersionedUrl()));
|
||||
}
|
||||
} else if (resource.getStatus() == PublicationStatus.RETIRED) {
|
||||
if (!params.hasParameterValue("warning-retired", resource.getVersionedUrl())) {
|
||||
params.addParameter("warning-retired", new UriType(resource.getVersionedUrl()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected AlternateCodesProcessingRules altCodeParams = new AlternateCodesProcessingRules(false);
|
||||
protected AlternateCodesProcessingRules allAltCodes = new AlternateCodesProcessingRules(true);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class ValidationProcessInfo {
|
|||
return issues;
|
||||
}
|
||||
public void addIssue(List<OperationOutcomeIssueComponent> issues) {
|
||||
issues.addAll(issues);
|
||||
this.issues.addAll(issues);
|
||||
|
||||
}
|
||||
public boolean hasErrors() {
|
||||
|
|
|
@ -97,7 +97,6 @@ import com.google.j2objc.annotations.ReflectionSupport.Level;
|
|||
public class ValueSetValidator extends ValueSetProcessBase {
|
||||
|
||||
private ValueSet valueset;
|
||||
private IWorkerContext context;
|
||||
private Map<String, ValueSetValidator> inner = new HashMap<>();
|
||||
private ValidationOptions options;
|
||||
private ValidationContextCarrier localContext;
|
||||
|
@ -215,7 +214,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
} else {
|
||||
c.setUserData("cs", cs);
|
||||
res = validateCode(path+".coding["+i+"]", c, cs, vcc);
|
||||
res = validateCode(path+".coding["+i+"]", c, cs, vcc, info);
|
||||
}
|
||||
info.getIssues().addAll(res.getIssues());
|
||||
i++;
|
||||
|
@ -229,7 +228,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
|
||||
for (Coding c : code.getCoding()) {
|
||||
b.append(c.getSystem()+(c.hasVersion() ? "|"+c.getVersion() : "")+"#"+c.getCode());
|
||||
Boolean ok = codeInValueSet(c.getSystem(), c.getVersion(), c.getCode(), info);
|
||||
Boolean ok = codeInValueSet(path, c.getSystem(), c.getVersion(), c.getCode(), info);
|
||||
if (ok == null && result != null && result == false) {
|
||||
result = null;
|
||||
} else if (ok != null && ok) {
|
||||
|
@ -338,30 +337,6 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
return versionTest == null && VersionUtilities.versionsMatch(versionTest, versionActual);
|
||||
}
|
||||
|
||||
private List<OperationOutcomeIssueComponent> makeIssue(IssueSeverity level, IssueType type, String location, String message) {
|
||||
OperationOutcomeIssueComponent result = new OperationOutcomeIssueComponent();
|
||||
switch (level) {
|
||||
case ERROR:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR);
|
||||
break;
|
||||
case FATAL:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL);
|
||||
break;
|
||||
case INFORMATION:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION);
|
||||
break;
|
||||
case WARNING:
|
||||
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
|
||||
break;
|
||||
}
|
||||
result.setCode(type);
|
||||
result.addLocation(location);
|
||||
result.getDetails().setText(message);
|
||||
ArrayList<OperationOutcomeIssueComponent> list = new ArrayList<>();
|
||||
list.add(result);
|
||||
return list;
|
||||
}
|
||||
|
||||
public ValidationResult validateCode(Coding code) throws FHIRException {
|
||||
return validateCode("Coding", code);
|
||||
}
|
||||
|
@ -374,7 +349,9 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
boolean inExpansion = false;
|
||||
boolean inInclude = false;
|
||||
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
ValidationProcessInfo info = new ValidationProcessInfo(issues);
|
||||
VersionInfo vi = new VersionInfo(this);
|
||||
checkCanonical(issues, path, valueset);
|
||||
|
||||
String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull();
|
||||
if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) {
|
||||
|
@ -434,6 +411,8 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
checkCanonical(issues, path, cs);
|
||||
}
|
||||
if (cs != null && cs.hasSupplements()) {
|
||||
String msg = context.formatMessage(I18nConstants.CODESYSTEM_CS_NO_SUPPLEMENT, cs.getUrl());
|
||||
|
@ -461,7 +440,8 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
// we can't validate that here.
|
||||
throw new FHIRException("Unable to evaluate based on empty code system");
|
||||
}
|
||||
res = validateCode(path, code, cs, null);
|
||||
res = validateCode(path, code, cs, null, info);
|
||||
res.setIssues(issues);
|
||||
} else if (cs == null && valueset.hasExpansion() && inExpansion) {
|
||||
// we just take the value set as face value then
|
||||
res = new ValidationResult(system, wv, new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay()), code.getDisplay());
|
||||
|
@ -481,12 +461,11 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
String wv = vi.getVersion(system, code.getVersion());
|
||||
|
||||
ValidationProcessInfo info = new ValidationProcessInfo(issues);
|
||||
|
||||
// then, if we have a value set, we check it's in the value set
|
||||
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
|
||||
if ((res==null || res.isOk())) {
|
||||
Boolean ok = codeInValueSet(system, wv, code.getCode(), info);
|
||||
Boolean ok = codeInValueSet(path, system, wv, code.getCode(), info);
|
||||
if (ok == null || !ok) {
|
||||
if (res == null) {
|
||||
res = new ValidationResult((IssueSeverity) null, null, info.getIssues());
|
||||
|
@ -654,7 +633,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
return false;
|
||||
}
|
||||
|
||||
private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc) {
|
||||
private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc, ValidationProcessInfo info) {
|
||||
ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), allAltCodes);
|
||||
if (cc == null) {
|
||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
|
@ -669,6 +648,10 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
if (vcc != null) {
|
||||
vcc.addCoding(vc);
|
||||
}
|
||||
if (CodeSystemUtilities.isInactive(cs, cc)) {
|
||||
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.EXPIRED, path, context.formatMessage(I18nConstants.INACTIVE_CODE_WARNING, cc.getCode())));
|
||||
}
|
||||
boolean ws = false;
|
||||
if (code.getDisplay() == null) {
|
||||
return new ValidationResult(code.getSystem(), cs.getVersion(), cc, vc.getDisplay());
|
||||
}
|
||||
|
@ -677,14 +660,20 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
b.append("'"+cc.getDisplay()+"'");
|
||||
if (code.getDisplay().equalsIgnoreCase(cc.getDisplay())) {
|
||||
return new ValidationResult(code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs));
|
||||
} else if (Utilities.normalize(code.getDisplay()).equals(Utilities.normalize(cc.getDisplay()))) {
|
||||
ws = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (ConceptDefinitionDesignationComponent ds : cc.getDesignation()) {
|
||||
if (isOkLanguage(ds.getLanguage())) {
|
||||
b.append("'"+ds.getValue()+"'");
|
||||
if (code.getDisplay().equalsIgnoreCase(ds.getValue())) {
|
||||
return new ValidationResult(code.getSystem(),cs.getVersion(), cc, getPreferredDisplay(cc, cs));
|
||||
}
|
||||
if (Utilities.normalize(code.getDisplay()).equalsIgnoreCase(Utilities.normalize(ds.getValue()))) {
|
||||
ws = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// also check to see if the value set has another display
|
||||
|
@ -711,7 +700,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
String msg = context.formatMessagePlural(options.getLanguages().size(), I18nConstants.NO_VALID_DISPLAY_FOUND, code.getSystem(), code.getCode(), code.getDisplay(), options.langSummary());
|
||||
return new ValidationResult(IssueSeverity.WARNING, msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path+".display", msg));
|
||||
} else {
|
||||
String msg = context.formatMessagePlural(b.count(), I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF, code.getSystem(), code.getCode(), b.toString(), code.getDisplay(), options.langSummary());
|
||||
String msg = context.formatMessagePlural(b.count(), ws ? I18nConstants.DISPLAY_NAME_WS_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF : I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF, code.getSystem(), code.getCode(), b.toString(), code.getDisplay(), options.langSummary());
|
||||
return new ValidationResult(dispWarningStatus(), msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(dispWarning(), IssueType.INVALID, path+".display", msg));
|
||||
}
|
||||
}
|
||||
|
@ -982,14 +971,11 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
return true;
|
||||
}
|
||||
|
||||
public Boolean codeInValueSet(String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
return codeInValueSet("code", system, version, code, info);
|
||||
}
|
||||
|
||||
public Boolean codeInValueSet(String path, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
if (valueset == null) {
|
||||
return false;
|
||||
}
|
||||
checkCanonical(info.getIssues(), path, valueset);
|
||||
Boolean result = false;
|
||||
VersionInfo vi = new VersionInfo(this);
|
||||
|
||||
|
@ -1029,15 +1015,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
if (isValueSetUnionImports()) {
|
||||
ok = false;
|
||||
for (UriType uri : vsi.getValueSet()) {
|
||||
if (inImport(uri.getValue(), system, version, code)) {
|
||||
if (inImport(path, uri.getValue(), system, version, code, info)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok = inImport(vsi.getValueSet().get(0).getValue(), system, version, code);
|
||||
ok = inImport(path, vsi.getValueSet().get(0).getValue(), system, version, code, info);
|
||||
for (int i = 1; i < vsi.getValueSet().size(); i++) {
|
||||
UriType uri = vsi.getValueSet().get(i);
|
||||
ok = ok && inImport(uri.getValue(), system, version, code);
|
||||
ok = ok && inImport(path, uri.getValue(), system, version, code, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1097,6 +1083,13 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
return null;
|
||||
}
|
||||
} else {
|
||||
checkCanonical(info.getIssues(), path, cs);
|
||||
if (valueset.getCompose().hasInactive() && !valueset.getCompose().getInactive()) {
|
||||
if (CodeSystemUtilities.isInactive(cs, code)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (vsi.hasFilter()) {
|
||||
ok = true;
|
||||
for (ConceptSetFilterComponent f : vsi.getFilter()) {
|
||||
|
@ -1231,12 +1224,12 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
return vsc;
|
||||
}
|
||||
|
||||
private boolean inImport(String uri, String system, String version, String code) throws FHIRException {
|
||||
private boolean inImport(String path, String uri, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
ValueSetValidator vs = getVs(uri);
|
||||
if (vs == null) {
|
||||
return false;
|
||||
} else {
|
||||
Boolean ok = vs.codeInValueSet(system, version, code, null);
|
||||
Boolean ok = vs.codeInValueSet(path, system, version, code, info);
|
||||
return ok != null && ok;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class CompareUtilities extends BaseTestingUtilities {
|
|||
String result = compareXml(expected, actual);
|
||||
if (result != null && SHOW_DIFF) {
|
||||
String diff = getDiffTool();
|
||||
if (new File(diff).exists() || Utilities.isToken(diff)) {
|
||||
if (diff != null && new File(diff).exists() || Utilities.isToken(diff)) {
|
||||
Runtime.getRuntime().exec(new String[]{diff, expected, actual});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -668,7 +668,7 @@ public class FHIRPathEngine {
|
|||
if (sd == null) {
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, t);
|
||||
}
|
||||
types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl());
|
||||
types.addType(sd.getUrl());
|
||||
} else {
|
||||
String ctxt = t.substring(0, t.indexOf('.'));
|
||||
StructureDefinition sd = cu.findType(ctxt);
|
||||
|
@ -680,11 +680,10 @@ public class FHIRPathEngine {
|
|||
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, t);
|
||||
}
|
||||
if (ed.fixedType != null) {
|
||||
types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType);
|
||||
types.addType(ed.fixedType);
|
||||
} else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) {
|
||||
types = new TypeDetails(CollectionStatus.SINGLETON, sd.getType()+"#"+t);
|
||||
types.addType(sd.getType()+"#"+t);
|
||||
} else {
|
||||
types = new TypeDetails(CollectionStatus.SINGLETON);
|
||||
for (TypeRefComponent tt : ed.getDefinition().getType()) {
|
||||
types.addType(tt.getCode());
|
||||
}
|
||||
|
@ -3545,7 +3544,7 @@ public class FHIRPathEngine {
|
|||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime);
|
||||
case Resolve : {
|
||||
checkContextReference(focus, "resolve", exp);
|
||||
return new TypeDetails(CollectionStatus.ORDERED, "DomainResource");
|
||||
return new TypeDetails(focus.getCollectionStatus(), "Resource");
|
||||
}
|
||||
case Extension : {
|
||||
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
|
||||
|
|
|
@ -256,4 +256,34 @@ public class XVerExtensionManager {
|
|||
return v.length() == 3 && Character.isDigit(v.charAt(0)) && v.charAt(1) == '.' && Character.isDigit(v.charAt(2));
|
||||
}
|
||||
|
||||
public String getReference(String url) {
|
||||
String version = getVersion(url);
|
||||
String base = VersionUtilities.getSpecUrl(version);
|
||||
if (base == null) {
|
||||
return null;
|
||||
} else {
|
||||
String path = url.substring(url.indexOf("-")+1);
|
||||
if (!path.contains(".")) {
|
||||
return null;
|
||||
}
|
||||
String type = path.substring(0, path.indexOf("."));
|
||||
if (Utilities.existsInList(type, "Annotation", "Attachment", "Identifier", "CodeableConcept", "Coding", "Quantity", "Duration", "Range", "Period", "Ratio", "RatioRange", "SampledData", "Signature", "HumanName", "Address", "ContactPoint", "Timing")) {
|
||||
return Utilities.pathURL(base, "datatypes-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
|
||||
}
|
||||
if (Utilities.existsInList(type, "Element", "BackboneElement", "BackboneType", "PrimitiveType", "DataType", "Base")) {
|
||||
return Utilities.pathURL(base, "types-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
|
||||
}
|
||||
if (Utilities.existsInList(type, "UsageContext", "RelatedArtifact", "DataRequirement", "ParameterDefinition", "TriggerDefinition", "Expression", "ContactDetail", "ExtendedContactDetail", "VirtualServiceDetail", "Availability", "MonetaryComponent", "Contributor")) {
|
||||
return Utilities.pathURL(base, "metadatatypes-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
|
||||
}
|
||||
if (Utilities.existsInList(type, "Reference", "CodeableReference")) {
|
||||
return Utilities.pathURL(base, "references-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
|
||||
}
|
||||
if (Utilities.existsInList(type, "Meta")) {
|
||||
return Utilities.pathURL(base, "resource-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
|
||||
}
|
||||
return Utilities.pathURL(base, type.toLowerCase()+"-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -149,7 +149,7 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
assertCanonicalResourceEquals(terminologyCapabilities, terminologyCacheB.getTerminologyCapabilities());
|
||||
assertCanonicalResourceEquals(capabilityStatement, terminologyCacheB.getCapabilityStatement());
|
||||
|
||||
assertValidationResultEquals(codingResultA, terminologyCacheB.getValidation( terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, coding, valueSet, new Parameters())));
|
||||
assertValidationResultEquals(codingResultA, terminologyCacheB.getValidation(terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, coding, valueSet, new Parameters())));
|
||||
assertValidationResultEquals(codeableConceptResultA, terminologyCacheB.getValidation(terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, concept, valueSet, new Parameters())));
|
||||
assertExpansionOutcomeEquals(expansionOutcomeA,terminologyCacheB.getExpansion(terminologyCacheA.generateExpandToken(valueSet, true)));
|
||||
}
|
||||
|
|
|
@ -12,3 +12,42 @@ e: {
|
|||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "urn:ietf:bcp:47"
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "urn:ietf:bcp:47"
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "urn:ietf:bcp:47"
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -44,3 +44,138 @@ e: {
|
|||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "http://loinc.org",
|
||||
"concept" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "A."
|
||||
}],
|
||||
"code" : "LA20752-4",
|
||||
"display" : "Within 24 hours"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "B."
|
||||
}],
|
||||
"code" : "LA20753-2",
|
||||
"display" : "After 24 hours but before 3 days"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "C."
|
||||
}],
|
||||
"code" : "LA20754-0",
|
||||
"display" : "Three days or later"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "D."
|
||||
}],
|
||||
"code" : "LA4489-6",
|
||||
"display" : "Unknown"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "http://loinc.org",
|
||||
"concept" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "A."
|
||||
}],
|
||||
"code" : "LA20752-4",
|
||||
"display" : "Within 24 hours"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "B."
|
||||
}],
|
||||
"code" : "LA20753-2",
|
||||
"display" : "After 24 hours but before 3 days"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "C."
|
||||
}],
|
||||
"code" : "LA20754-0",
|
||||
"display" : "Three days or later"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "D."
|
||||
}],
|
||||
"code" : "LA4489-6",
|
||||
"display" : "Unknown"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "http://loinc.org",
|
||||
"concept" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "A."
|
||||
}],
|
||||
"code" : "LA20752-4",
|
||||
"display" : "Within 24 hours"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "B."
|
||||
}],
|
||||
"code" : "LA20753-2",
|
||||
"display" : "After 24 hours but before 3 days"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "C."
|
||||
}],
|
||||
"code" : "LA20754-0",
|
||||
"display" : "Three days or later"
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
|
||||
"valueString" : "D."
|
||||
}],
|
||||
"code" : "LA4489-6",
|
||||
"display" : "Unknown"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -12,3 +12,42 @@ e: {
|
|||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "urn:ietf:bcp:13"
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "urn:ietf:bcp:13"
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "urn:ietf:bcp:13"
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -96,3 +96,294 @@ e: {
|
|||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "http://unitsofmeasure.org",
|
||||
"concept" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "second"
|
||||
}],
|
||||
"code" : "s",
|
||||
"display" : "second",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "秒"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "minute"
|
||||
}],
|
||||
"code" : "min",
|
||||
"display" : "minute",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "分钟"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "hour"
|
||||
}],
|
||||
"code" : "h",
|
||||
"display" : "hour",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "小时"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "day"
|
||||
}],
|
||||
"code" : "d",
|
||||
"display" : "day",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "天"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "week"
|
||||
}],
|
||||
"code" : "wk",
|
||||
"display" : "week",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "星期"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "month - Normal practice is to use the 'mo' code as a calendar month when calculating the next occurrence."
|
||||
}],
|
||||
"code" : "mo",
|
||||
"display" : "month",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "月"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "year"
|
||||
}],
|
||||
"code" : "a",
|
||||
"display" : "year",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "年"
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "http://unitsofmeasure.org",
|
||||
"concept" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "second"
|
||||
}],
|
||||
"code" : "s",
|
||||
"display" : "second",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "秒"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "minute"
|
||||
}],
|
||||
"code" : "min",
|
||||
"display" : "minute",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "分钟"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "hour"
|
||||
}],
|
||||
"code" : "h",
|
||||
"display" : "hour",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "小时"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "day"
|
||||
}],
|
||||
"code" : "d",
|
||||
"display" : "day",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "天"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "week"
|
||||
}],
|
||||
"code" : "wk",
|
||||
"display" : "week",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "星期"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "month - Normal practice is to use the 'mo' code as a calendar month when calculating the next occurrence."
|
||||
}],
|
||||
"code" : "mo",
|
||||
"display" : "month",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "月"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "year"
|
||||
}],
|
||||
"code" : "a",
|
||||
"display" : "year",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "年"
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"hierarchical" : false, "valueSet" :{
|
||||
"resourceType" : "ValueSet",
|
||||
"compose" : {
|
||||
"inactive" : true,
|
||||
"include" : [{
|
||||
"system" : "http://unitsofmeasure.org",
|
||||
"concept" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "second"
|
||||
}],
|
||||
"code" : "s",
|
||||
"display" : "second",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "秒"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "minute"
|
||||
}],
|
||||
"code" : "min",
|
||||
"display" : "minute",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "分钟"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "hour"
|
||||
}],
|
||||
"code" : "h",
|
||||
"display" : "hour",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "小时"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "day"
|
||||
}],
|
||||
"code" : "d",
|
||||
"display" : "day",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "天"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "week"
|
||||
}],
|
||||
"code" : "wk",
|
||||
"display" : "week",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "星期"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "month - Normal practice is to use the 'mo' code as a calendar month when calculating the next occurrence."
|
||||
}],
|
||||
"code" : "mo",
|
||||
"display" : "month",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "月"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
|
||||
"valueString" : "year"
|
||||
}],
|
||||
"code" : "a",
|
||||
"display" : "year",
|
||||
"designation" : [{
|
||||
"language" : "zh",
|
||||
"value" : "年"
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}}####
|
||||
e: {
|
||||
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -65,8 +65,9 @@ public class CSFile extends File {
|
|||
//attempt to open a file triggers a directory listing
|
||||
if (exists())
|
||||
{
|
||||
if(!this.getCanonicalFile().getName().equals(this.getName()))
|
||||
if(!this.getCanonicalFile().getName().equals(this.getName())) {
|
||||
throw new Error("Case mismatch of file "+ pathname+": found "+this.getCanonicalFile().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
|
||||
public enum StandardsStatus {
|
||||
|
||||
EXTERNAL, INFORMATIVE, DRAFT, TRIAL_USE, DEPRECATED, NORMATIVE;
|
||||
EXTERNAL, INFORMATIVE, DRAFT, TRIAL_USE, DEPRECATED, NORMATIVE, WITHDRAWN;
|
||||
|
||||
public String toDisplay() {
|
||||
switch (this) {
|
||||
|
@ -51,6 +51,8 @@ public enum StandardsStatus {
|
|||
return "External";
|
||||
case DEPRECATED:
|
||||
return "Deprecated";
|
||||
case WITHDRAWN:
|
||||
return "Withdrawn";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
@ -66,9 +68,11 @@ public enum StandardsStatus {
|
|||
case INFORMATIVE:
|
||||
return "informative";
|
||||
case DEPRECATED:
|
||||
return "deprecated";
|
||||
return "deprecated";
|
||||
case EXTERNAL:
|
||||
return "external";
|
||||
case WITHDRAWN:
|
||||
return "Withdrawn";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
@ -93,6 +97,8 @@ public enum StandardsStatus {
|
|||
return EXTERNAL;
|
||||
if (value.equalsIgnoreCase("DEPRECATED"))
|
||||
return DEPRECATED;
|
||||
if (value.equalsIgnoreCase("WITHDRAWN"))
|
||||
return WITHDRAWN;
|
||||
throw new FHIRException("Incorrect Standards Status '"+value+"'");
|
||||
}
|
||||
|
||||
|
@ -110,6 +116,8 @@ public enum StandardsStatus {
|
|||
return "XD";
|
||||
case EXTERNAL:
|
||||
return "X";
|
||||
case WITHDRAWN:
|
||||
return "W";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
@ -125,6 +133,7 @@ public enum StandardsStatus {
|
|||
case INFORMATIVE:
|
||||
return "#ffffe6";
|
||||
case DEPRECATED:
|
||||
case WITHDRAWN:
|
||||
return "#ffcccc";
|
||||
case EXTERNAL:
|
||||
return "#e6ffff";
|
||||
|
@ -143,6 +152,7 @@ public enum StandardsStatus {
|
|||
case INFORMATIVE:
|
||||
return "#ffffec";
|
||||
case DEPRECATED:
|
||||
case WITHDRAWN:
|
||||
return "#ffcccc";
|
||||
case EXTERNAL:
|
||||
return "#ecffff";
|
||||
|
@ -159,6 +169,8 @@ public enum StandardsStatus {
|
|||
return (tgtSS == NORMATIVE || tgtSS == EXTERNAL );
|
||||
if (this == DEPRECATED)
|
||||
return (tgtSS == DEPRECATED );
|
||||
if (this == WITHDRAWN)
|
||||
return (tgtSS == WITHDRAWN );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -307,7 +307,18 @@ public class Utilities {
|
|||
CSFile src = new CSFile(sourceFolder);
|
||||
if (!src.exists())
|
||||
throw new FHIRException("Folder " + sourceFolder + " not found");
|
||||
createDirectory(destFolder);
|
||||
File dst = new File(destFolder);
|
||||
if(!dst.getCanonicalFile().getName().equals(dst.getName())) {
|
||||
File tmp = new File(destFolder+System.currentTimeMillis());
|
||||
if (!dst.renameTo(tmp)) {
|
||||
throw new IOException("fixing case from "+dst.getCanonicalFile().getName()+" to "+tmp.getName()+" failed");
|
||||
}
|
||||
if (!tmp.renameTo(dst)) {
|
||||
throw new IOException("fixing case from "+tmp.getCanonicalFile().getName()+" to "+dst.getName()+" failed");
|
||||
}
|
||||
} else if (!dst.exists()) {
|
||||
createDirectory(destFolder);
|
||||
}
|
||||
|
||||
String[] files = src.list();
|
||||
for (String f : files) {
|
||||
|
@ -318,7 +329,7 @@ public class Utilities {
|
|||
} else {
|
||||
if (notifier != null)
|
||||
notifier.copyFile(sourceFolder + File.separator + f, destFolder + File.separator + f);
|
||||
copyFile(new CSFile(sourceFolder + File.separator + f), new CSFile(destFolder + File.separator + f));
|
||||
copyFile(new CSFile(sourceFolder + File.separator + f), new /*CS*/File(destFolder + File.separator + f)); // case doesn't have to match on the target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -358,6 +369,10 @@ public class Utilities {
|
|||
createDirectory(destFile.getParent());
|
||||
}
|
||||
destFile.createNewFile();
|
||||
} else if (!destFile.getCanonicalFile().getName().equals(destFile.getName())) {
|
||||
// case mismatch
|
||||
destFile.delete();
|
||||
destFile.createNewFile();
|
||||
}
|
||||
|
||||
FileInputStream source = null;
|
||||
|
@ -2112,4 +2127,8 @@ public class Utilities {
|
|||
return url.contains("/") ? url.substring(url.lastIndexOf("/")+1) : url;
|
||||
}
|
||||
|
||||
public static String escapeSql(String s) {
|
||||
return s.replace("'", "''");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ public class I18nConstants {
|
|||
public static final String DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES = "Discriminator__is_based_on_type_but_slice__in__has_no_types";
|
||||
public static final String DISCRIMINATOR_BAD_PATH = "DISCRIMINATOR_BAD_PATH";
|
||||
public static final String DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF = "Display_Name_for__should_be_one_of__instead_of";
|
||||
public static final String DISPLAY_NAME_WS_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF = "Display_Name_WS_for__should_be_one_of__instead_of";
|
||||
public static final String DOCUMENT = "documentmsg";
|
||||
public static final String DOCUMENT_DATE_REQUIRED = "Bundle_Document_Date_Missing";
|
||||
public static final String DOCUMENT_DATE_REQUIRED_HTML = "Bundle_Document_Date_Missing_html";
|
||||
|
@ -949,9 +950,12 @@ public class I18nConstants {
|
|||
public static final String ED_INVARIANT_KEY_ALREADY_USED = "ED_INVARIANT_KEY_ALREADY_USED";
|
||||
public static final String FHIRPATH_OFTYPE_IMPOSSIBLE = "FHIRPATH_OFTYPE_IMPOSSIBLE";
|
||||
public static final String ED_SEARCH_EXPRESSION_ERROR = "ED_SEARCH_EXPRESSION_ERROR";
|
||||
|
||||
|
||||
|
||||
public static final String SD_EXTENSION_URL_MISMATCH = "SD_EXTENSION_URL_MISMATCH";
|
||||
public static final String MSG_DEPRECATED = "MSG_DEPRECATED";
|
||||
public static final String MSG_WITHDRAWN = "MSG_WITHDRAWN";
|
||||
public static final String MSG_RETIRED = "MSG_RETIRED";
|
||||
public static final String INACTIVE_CODE_WARNING = "INACTIVE_CODE_WARNING";
|
||||
public static final String SD_EXTENSION_URL_MISSING = "SD_EXTENSION_URL_MISSING";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -297,6 +297,7 @@ public class NpmPackage {
|
|||
private Map<String, Object> userData;
|
||||
private boolean minimalMemory;
|
||||
private int size;
|
||||
private boolean warned = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -1266,6 +1267,11 @@ public class NpmPackage {
|
|||
return Utilities.existsInList(npm.asString("type"), "fhir.core", "Core");
|
||||
}
|
||||
|
||||
public boolean isCoreExamples() {
|
||||
return name().startsWith("hl7.fhir.r") && name().endsWith(".examples");
|
||||
}
|
||||
|
||||
|
||||
public boolean isTx() {
|
||||
return npm.asString("name").startsWith("hl7.terminology");
|
||||
}
|
||||
|
@ -1369,5 +1375,14 @@ public class NpmPackage {
|
|||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public boolean isWarned() {
|
||||
return warned;
|
||||
}
|
||||
|
||||
public void setWarned(boolean warned) {
|
||||
this.warned = warned;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -859,6 +859,50 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
|||
this.ignorableError = ignorableError;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean matches(ValidationMessage other) {
|
||||
if (location == null) {
|
||||
if (other.location != null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
String l1 = preprocessLocation(location);
|
||||
String l2 = preprocessLocation(other.location);
|
||||
if (!l1.equals(l2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (message == null) {
|
||||
if (other.message != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!message.equals(other.message)) {
|
||||
return false;
|
||||
}
|
||||
if (messageId == null) {
|
||||
if (other.messageId != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!messageId.equals(other.messageId)) {
|
||||
return false;
|
||||
}
|
||||
if (type != other.type) {
|
||||
return false;
|
||||
}
|
||||
if (level != other.level) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String preprocessLocation(String loc) {
|
||||
// some locations are prefixes with a location but they're not different since the location is fixed where .match is called from
|
||||
if (loc.contains(": ")) {
|
||||
return loc.substring(loc.indexOf(": ")+2);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -171,7 +171,7 @@ Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0
|
|||
Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1}
|
||||
Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server
|
||||
Terminology_TX_NoValid_15A = The value provided (''{0}'') could not be validated because the code system {1} is not known
|
||||
Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1}, and a code is required from this value set){2}
|
||||
Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1}, and a code is required from this value set {2}
|
||||
Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1}, and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) {2}
|
||||
Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1}, and a code is recommended to come from this value set){2}
|
||||
Terminology_TX_NoValid_2_CC = None of the codings provided are in the value set {0}, and a coding should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) (codes = {1})
|
||||
|
@ -468,6 +468,8 @@ Error_parsing_ = Error parsing {0}:{1}
|
|||
Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__ = Unable to connect to terminology server. Use parameter ''-tx n/a'' to run without using terminology services to validate LOINC, SNOMED, ICD-X etc. Error = {0}
|
||||
Display_Name_for__should_be_one_of__instead_of_one = Wrong Display Name ''{4}'' for {1}#{2} - should be {3} (for the language(s) ''{5}'')
|
||||
Display_Name_for__should_be_one_of__instead_of_other = Wrong Display Name ''{4}'' for {1}#{2} - should be one of {0} choices: {3} (for the language(s) ''{5}'')
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_one = Wrong whitespace in Display Name ''{4}'' for {1}#{2} - should be {3} (for the language(s) ''{5}'')
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_other = Wrong whitespace in Display Name ''{4}'' for {1}#{2} - should be one of {0} choices: {3} (for the language(s) ''{5}'')
|
||||
Unknown_Code__in_ = Unknown Code ''{0}'' in the system ''{1}''
|
||||
UNKNOWN_CODE__IN_FRAGMENT = Unknown Code ''{0}'' in the system ''{1}'' - note that the code system is labeled as a fragment, so the code may be valid in some other fragment
|
||||
Code_found_in_expansion_however_ = Code found in expansion, however: {0}
|
||||
|
@ -1004,4 +1006,11 @@ ED_INVARIANT_DIFF_NO_SOURCE = The invariant {0} defined in the differential must
|
|||
FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT = The left side is inherently a collection, and so the expression ''{0}'' may fail or return false if there is more than one item in the content being evaluated
|
||||
FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT = The right side is inherently a collection, and so this expression ''{0}'' may fail or return false if there is more than one item in the content being evaluated
|
||||
FHIRPATH_OFTYPE_IMPOSSIBLE = The type specified in ofType is {1} which is not a possible candidate for the existing types ({0}) in the expression {2}. Check the paths and types to be sure this is what is intended
|
||||
ED_SEARCH_EXPRESSION_ERROR = Error in search expression ''{0}'': {1}
|
||||
ED_SEARCH_EXPRESSION_ERROR = Error in search expression ''{0}'': {1}
|
||||
SD_EXTENSION_URL_MISMATCH = The fixed value for the extension URL is {1} which doesn''t match the canonical URL {0}
|
||||
SD_EXTENSION_URL_MISSING = The value of Extension.url is not fixed to the extension URL {0}
|
||||
MSG_DEPRECATED = Reference to deprecated item {0}
|
||||
MSG_WITHDRAWN = Reference to withdrawn item {0}
|
||||
MSG_RETIRED = Reference to retired item {0}
|
||||
INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active
|
||||
SD_ED_TYPE_PROFILE_WRONG_TYPE = The type {0} is not in the list of allowed types {1} in the profile {2}
|
||||
|
|
|
@ -831,4 +831,7 @@ PRIMITIVE_VALUE_ALTERNATIVES_MESSAGE_many =
|
|||
PRIMITIVE_VALUE_ALTERNATIVES_MESSAGE_other =
|
||||
UNICODE_XML_BAD_CHARS_one =
|
||||
UNICODE_XML_BAD_CHARS_many =
|
||||
UNICODE_XML_BAD_CHARS_other =
|
||||
UNICODE_XML_BAD_CHARS_other =
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_one =
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_many =
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_other =
|
||||
|
|
|
@ -422,5 +422,46 @@ class UtilitiesTest {
|
|||
Assertions.assertFalse("\u0009\n\u000B\u000C\r\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000".matches(".+"));
|
||||
Assertions.assertFalse("\u0009\n\u000B\u000C\r\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000".matches("^.+$"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("directory copy case tests")
|
||||
void testFDirectoryCopy() throws IOException {
|
||||
String src = Utilities.path("[tmp]", "test", "copy-source");
|
||||
String dst = Utilities.path("[tmp]", "test", "copy-dest");
|
||||
makeDir (src);
|
||||
makeFile(Utilities.path(src, "Test.txt"), "source1");
|
||||
makeDir (Utilities.path(src, "SUB"));
|
||||
makeFile(Utilities.path(src, "SUB", "TEST.txt"), "source2");
|
||||
|
||||
makeDir (dst);
|
||||
makeFile(Utilities.path(dst, "test.txt"), "dest1");
|
||||
makeDir (Utilities.path(dst, "sub"));
|
||||
makeFile(Utilities.path(dst, "sub", "test.txt"), "dest2");
|
||||
|
||||
Utilities.copyDirectory(src, dst, null);
|
||||
|
||||
checkDir (dst);
|
||||
checkFile(Utilities.path(dst, "Test.txt"), "source1");
|
||||
checkDir (Utilities.path(dst, "SUB"));
|
||||
checkFile(Utilities.path(dst, "SUB", "TEST.txt"), "source2");
|
||||
}
|
||||
|
||||
private void checkFile(String path, String content) throws IOException {
|
||||
Assertions.assertTrue(new CSFile(path).exists());
|
||||
Assertions.assertEquals(content, TextFile.fileToString(path));
|
||||
}
|
||||
|
||||
private void checkDir(String path) throws IOException {
|
||||
Assertions.assertTrue(new CSFile(path).exists());
|
||||
}
|
||||
|
||||
private void makeFile(String path, String content) throws IOException {
|
||||
TextFile.stringToFile(content, path);
|
||||
}
|
||||
|
||||
private void makeDir(String path) throws IOException {
|
||||
Utilities.createDirectory(path);
|
||||
Utilities.clearDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -520,12 +520,14 @@ public class IgLoader implements IValidationEngineLoader {
|
|||
}
|
||||
}
|
||||
|
||||
if (loadInContext) {
|
||||
// getContext().getLoadedPackages().add(pi.name() + "#" + pi.version());
|
||||
getContext().loadFromPackage(pi, ValidatorUtils.loaderForVersion(pi.fhirVersion()));
|
||||
}
|
||||
for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "SearchParameter", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) {
|
||||
res.put(s, TextFile.streamToBytes(pi.load("package", s)));
|
||||
if (!pi.isCoreExamples()) {
|
||||
if (loadInContext) {
|
||||
// getContext().getLoadedPackages().add(pi.name() + "#" + pi.version());
|
||||
getContext().loadFromPackage(pi, ValidatorUtils.loaderForVersion(pi.fhirVersion()));
|
||||
}
|
||||
for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "SearchParameter", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) {
|
||||
res.put(s, TextFile.streamToBytes(pi.load("package", s)));
|
||||
}
|
||||
}
|
||||
String ini = "[FHIR]\r\nversion=" + pi.fhirVersion() + "\r\n";
|
||||
res.put("version.info", ini.getBytes());
|
||||
|
|
|
@ -2024,8 +2024,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return true;
|
||||
}
|
||||
plist.add(p);
|
||||
|
||||
}
|
||||
Collections.sort(plist); // logical paths are a set, but we want a predictable order for error messages
|
||||
|
||||
for (StructureDefinitionContextComponent ctxt : fixContexts(extUrl, definition.getContext())) {
|
||||
if (ok) {
|
||||
|
@ -2038,36 +2038,45 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (en.contains("#")) {
|
||||
pu = en.substring(0, en.indexOf("#"));
|
||||
en = en.substring(en.indexOf("#")+1);
|
||||
} else {
|
||||
//pu = en;
|
||||
}
|
||||
if (Utilities.existsInList(en, "Element", "Any")) {
|
||||
ok = true;
|
||||
} else if (en.equals("Resource") && container.isResource()) {
|
||||
ok = true;
|
||||
} else if (en.equals("CanonicalResource") && VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(stack.getLiteralPath())) {
|
||||
ok = true;
|
||||
} else if (plist.contains(en) && pu == null) {
|
||||
ok = true;
|
||||
}
|
||||
if (checkConformsToProfile(appContext, errors, resource, container, stack, extUrl, ctxt.getExpression(), pu)) {
|
||||
for (String p : plist) {
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
if (p.equals(en)) {
|
||||
ok = true;
|
||||
} else {
|
||||
String pn = p;
|
||||
String pt = "";
|
||||
if (p.contains(".")) {
|
||||
pn = p.substring(0, p.indexOf("."));
|
||||
pt = p.substring(p.indexOf("."));
|
||||
|
||||
if (!ok) {
|
||||
if (checkConformsToProfile(appContext, errors, resource, container, stack, extUrl, ctxt.getExpression(), pu)) {
|
||||
for (String p : plist) {
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
StructureDefinition sd = context.fetchTypeDefinition(pn);
|
||||
while (sd != null) {
|
||||
if ((sd.getType() + pt).equals(en)) {
|
||||
ok = true;
|
||||
break;
|
||||
if (p.equals(en)) {
|
||||
ok = true;
|
||||
} else {
|
||||
String pn = p;
|
||||
String pt = "";
|
||||
if (p.contains(".")) {
|
||||
pn = p.substring(0, p.indexOf("."));
|
||||
pt = p.substring(p.indexOf("."));
|
||||
}
|
||||
if (sd.getBaseDefinition() != null) {
|
||||
sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd);
|
||||
} else {
|
||||
sd = null;
|
||||
StructureDefinition sd = context.fetchTypeDefinition(pn);
|
||||
while (sd != null) {
|
||||
if ((sd.getType() + pt).equals(en)) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
if (sd.getBaseDefinition() != null) {
|
||||
sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd);
|
||||
} else {
|
||||
sd = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5960,7 +5969,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (ed.hasSlicing()) {
|
||||
if (slicer != null && slicer.getPath().equals(ed.getPath())) {
|
||||
String errorContext = "profile " + profile.getVersionedUrl();
|
||||
if (!resource.getChildValue(ID).isEmpty()) {
|
||||
if (resource.hasChild(ID) && !resource.getChildValue(ID).isEmpty()) {
|
||||
errorContext += "; instance " + resource.getChildValue("id");
|
||||
}
|
||||
throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));
|
||||
|
|
|
@ -78,6 +78,8 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
StructureDefinition sd = null;
|
||||
String typeName = null;
|
||||
try {
|
||||
String url = src.getNamedChildValue("url");
|
||||
|
||||
sd = loadAsSD(src);
|
||||
checkExtensionContext(errors, src, stack);
|
||||
|
||||
|
@ -101,8 +103,8 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
for (ValidationMessage msg : msgs) {
|
||||
// we need to set the location for the context
|
||||
String loc = msg.getLocation();
|
||||
if (loc.contains("#")) {
|
||||
msg.setLocation(stack.getLiteralPath()+".differential.element.where(path = '"+loc.substring(loc.indexOf("#")+1)+"')");
|
||||
if (loc.startsWith("StructureDefinition.")) {
|
||||
msg.setLocation(stack.getLiteralPath()+loc.substring(loc.indexOf(".")));
|
||||
} else {
|
||||
msg.setLocation(stack.getLiteralPath());
|
||||
}
|
||||
|
@ -160,6 +162,20 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
// if this is defining an extension, make sure that the extension fixed value matches the URL
|
||||
String type = src.getNamedChildValue("type");
|
||||
if ("Extension".equals(type)) {
|
||||
String baseD = src.getNamedChildValue("baseDefinition");
|
||||
if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(baseD) && url != null) {
|
||||
String fixedUrl = getFixedValue(src);
|
||||
if (rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), fixedUrl != null, I18nConstants.SD_EXTENSION_URL_MISSING, url)) {
|
||||
ok = rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), url.equals(fixedUrl), I18nConstants.SD_EXTENSION_URL_MISMATCH, url, fixedUrl) && ok;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
|
||||
ok = false;
|
||||
|
@ -168,6 +184,19 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
}
|
||||
|
||||
|
||||
private String getFixedValue(Element src) {
|
||||
Element diff = src.getNamedChild("differential");
|
||||
if (diff != null) {
|
||||
for (Element ed : diff.getChildrenByName("element")) {
|
||||
String path = ed.getNamedChildValue("path");
|
||||
if ("Extension.url".equals(path)) {
|
||||
return ed.getNamedChildValue("fixed");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean validateInheritsObligationProfile(List<ValidationMessage> errors, Element extension, NodeStack stack, Element src) {
|
||||
String tgt = extension.getNamedChildValue("value");
|
||||
if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), tgt != null,
|
||||
|
|
|
@ -71,7 +71,7 @@ public class ValueSetValidator extends BaseValidator {
|
|||
List<Element> composes = vs.getChildrenByName("compose");
|
||||
int cc = 0;
|
||||
for (Element compose : composes) {
|
||||
ok = validateValueSetCompose(errors, compose, stack.push(compose, cc, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))) & ok;
|
||||
ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))) & ok;
|
||||
cc++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ package org.hl7.fhir.validation.instance.utils;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
|
@ -19,7 +21,7 @@ public class NodeStack {
|
|||
private Element element;
|
||||
private ElementDefinition extension;
|
||||
private String literalPath; // xpath format
|
||||
private List<String> logicalPaths; // dotted format, various entry points
|
||||
private Set<String> logicalPaths; // dotted format, various entry points
|
||||
private NodeStack parent;
|
||||
private ElementDefinition type;
|
||||
private String workingLang;
|
||||
|
@ -38,7 +40,7 @@ public class NodeStack {
|
|||
literalPath = (initialPath == null ? "" : initialPath+".") + element.getPath();
|
||||
workingLang = validationLanguage;
|
||||
if (!element.getName().equals(element.fhirType())) {
|
||||
logicalPaths = new ArrayList<>();
|
||||
logicalPaths = new HashSet<>();
|
||||
logicalPaths.add(element.fhirType());
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +81,8 @@ public class NodeStack {
|
|||
return literalPath == null ? "" : literalPath;
|
||||
}
|
||||
|
||||
public List<String> getLogicalPaths() {
|
||||
return logicalPaths == null ? new ArrayList<String>() : logicalPaths;
|
||||
public Set<String> getLogicalPaths() {
|
||||
return logicalPaths == null ? new HashSet<String>() : logicalPaths;
|
||||
}
|
||||
|
||||
private ElementDefinition getType() {
|
||||
|
@ -96,6 +98,9 @@ public class NodeStack {
|
|||
}
|
||||
|
||||
private NodeStack pushInternal(Element element, int count, ElementDefinition definition, ElementDefinition type, String sep) {
|
||||
if (definition == null & element.getProperty() != null) {
|
||||
definition = element.getProperty().getDefinition();
|
||||
}
|
||||
NodeStack res = new NodeStack(context);
|
||||
res.ids = ids;
|
||||
res.parent = this;
|
||||
|
@ -121,7 +126,7 @@ public class NodeStack {
|
|||
res.literalPath = res.literalPath.substring(0, res.literalPath.lastIndexOf(".")) + "." + en;;
|
||||
}
|
||||
}
|
||||
res.logicalPaths = new ArrayList<String>();
|
||||
res.logicalPaths = new HashSet<String>();
|
||||
if (type != null) {
|
||||
// type will be null if we on a stitching point of a contained resource, or if....
|
||||
res.type = type;
|
||||
|
@ -131,23 +136,48 @@ public class NodeStack {
|
|||
tn = element.fhirType();
|
||||
}
|
||||
for (String lp : getLogicalPaths()) {
|
||||
res.logicalPaths.add(lp + "." + t);
|
||||
if (t.endsWith("[x]")) {
|
||||
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + ".ofType("+type.getPath()+")");
|
||||
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + type.getPath());
|
||||
if (isRealPath(lp, t)) {
|
||||
res.logicalPaths.add(lp + "." + t);
|
||||
if (t.endsWith("[x]")) {
|
||||
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + ".ofType("+type.getPath()+")");
|
||||
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + type.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
res.logicalPaths.add(tn);
|
||||
} else if (definition != null) {
|
||||
for (String lp : getLogicalPaths()) {
|
||||
res.logicalPaths.add(lp + "." + element.getName());
|
||||
if (isRealPath(lp, element.getName())) {
|
||||
res.logicalPaths.add(lp + "." + element.getName());
|
||||
}
|
||||
}
|
||||
res.logicalPaths.add(definition.typeSummary());
|
||||
} else
|
||||
if (definition.hasContentReference()) {
|
||||
res.logicalPaths.add(definition.getContentReference().substring(definition.getContentReference().indexOf("#")+1));
|
||||
} else {
|
||||
res.logicalPaths.addAll(definition.typeList());
|
||||
}
|
||||
} else {
|
||||
res.logicalPaths.addAll(getLogicalPaths());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean isRealPath(String lp, String t) {
|
||||
if (Utilities.existsInList(lp, "Element")) {
|
||||
return Utilities.existsInList(t, "id", "extension");
|
||||
}
|
||||
if (Utilities.existsInList(lp, "BackboneElement", "BackboneType")) {
|
||||
return Utilities.existsInList(t, "modifierExtension");
|
||||
}
|
||||
if (Utilities.existsInList(lp, "Resource")) {
|
||||
return Utilities.existsInList(t, "id", "meta", "implicitRules", "language");
|
||||
}
|
||||
if (Utilities.existsInList(lp, "DomainResource")) {
|
||||
return Utilities.existsInList(t, "text", "contained", "extension", "modifierExtension");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setType(ElementDefinition type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@ package org.hl7.fhir.validation.special;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.hl7.fhir.ParametersParameter;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
|
@ -16,8 +20,14 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
|
|||
public class TxTesterSorters {
|
||||
|
||||
|
||||
|
||||
public static void sortParameters(Parameters po) {
|
||||
Collections.sort(po.getParameter(), new TxTesterSorters.ParameterSorter());
|
||||
for (ParametersParameterComponent p : po.getParameter()) {
|
||||
if (p.getResource() != null && p.getResource() instanceof OperationOutcome) {
|
||||
Collections.sort(((OperationOutcome) p.getResource()).getIssue(), new TxTesterSorters.OperationIssueSorter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,7 +53,24 @@ public class TxTesterSorters {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static class OperationIssueSorter implements Comparator<OperationOutcomeIssueComponent> {
|
||||
|
||||
@Override
|
||||
public int compare(OperationOutcomeIssueComponent o1, OperationOutcomeIssueComponent o2) {
|
||||
if (o1.hasSeverity() && o2.hasSeverity() && o1.getSeverity() != o2.getSeverity()) {
|
||||
return o1.getSeverity().compareTo(o2.getSeverity());
|
||||
}
|
||||
if (o1.hasCode() && o2.hasCode() && o1.getCode() != o2.getCode()) {
|
||||
return o1.getCode().compareTo(o2.getCode());
|
||||
}
|
||||
if (o1.getDetails().hasText() && o2.getDetails().hasText() && !o1.getDetails().getText().equals(o2.getDetails().getText())) {
|
||||
return o1.getDetails().getText().compareTo(o2.getDetails().getText());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DesignationSorter implements Comparator<ConceptReferenceDesignationComponent> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -107,7 +107,7 @@ public class SnapShotGenerationXTests {
|
|||
sort = "true".equals(test.getAttribute("sort"));
|
||||
fail = "true".equals(test.getAttribute("fail"));
|
||||
newSliceProcessing = !"false".equals(test.getAttribute("new-slice-processing"));
|
||||
debug = false; // "true".equals(test.getAttribute("debug"));
|
||||
debug = "true".equals(test.getAttribute("debug"));
|
||||
|
||||
id = test.getAttribute("id");
|
||||
include = test.getAttribute("include");
|
||||
|
@ -510,7 +510,7 @@ public class SnapShotGenerationXTests {
|
|||
pu.setAllowUnknownProfile(AllowUnknownProfile.ALL_TYPES);
|
||||
if (test.isSort()) {
|
||||
List<String> errors = new ArrayList<String>();
|
||||
int lastCount = output.getDifferential().getElement().size();
|
||||
// int lastCount = output.getDifferential().getElement().size();
|
||||
pu.sortDifferential(base, output, test.getSource().getName(), errors, false);
|
||||
if (errors.size() > 0)
|
||||
throw new FHIRException("Sort failed: " + errors.toString());
|
||||
|
|
|
@ -46,9 +46,9 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader {
|
|||
private JsonObject test;
|
||||
}
|
||||
|
||||
private static final String SERVER = FhirSettings.getTxFhirDevelopment();
|
||||
// private static final String SERVER = FhirSettings.getTxFhirLocal();
|
||||
// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir";
|
||||
private static final String SERVER = FhirSettings.getTxFhirDevelopment();
|
||||
// private static final String SERVER = FhirSettings.getTxFhirLocal();
|
||||
// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir";
|
||||
|
||||
|
||||
@Parameters(name = "{index}: id {0}")
|
||||
|
|
|
@ -563,7 +563,12 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
JsonObject oj = JsonTrackingParser.parse(json, null);
|
||||
java.add("outcome", oj);
|
||||
}
|
||||
JsonTrackingParser.write(manifest, new File(Utilities.path("[tmp]", "validator", "manifest.new.json")));
|
||||
|
||||
File newManifestFile = new File(Utilities.path("[tmp]", "validator", "manifest.new.json"));
|
||||
if (!newManifestFile.getParentFile().exists()) {
|
||||
newManifestFile.getParentFile().mkdir();
|
||||
}
|
||||
JsonTrackingParser.write(manifest, newManifestFile);
|
||||
}
|
||||
Assertions.fail("\r\n"+String.join("\r\n", fails));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
This suppresses CVEs related to a HAPI-FHIR parent pom that no longer exists in fhir-test-cases
|
||||
]]></notes>
|
||||
<packageUrl regex="true">^pkg:maven/org\.hl7\.fhir\.testcases/fhir\-test\-cases@.*$</packageUrl>
|
||||
<cve>CVE-2019-12741</cve>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
This suppresses CVEs related to a HAPI-FHIR parent pom that no longer exists in fhir-test-cases
|
||||
]]></notes>
|
||||
<packageUrl regex="true">^pkg:maven/org\.hl7\.fhir\.testcases/fhir\-test\-cases@.*$</packageUrl>
|
||||
<cve>CVE-2021-32053</cve>
|
||||
</suppress>
|
||||
</suppressions>
|
9
pom.xml
9
pom.xml
|
@ -14,13 +14,13 @@
|
|||
HAPI FHIR
|
||||
-->
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.0.24-SNAPSHOT</version>
|
||||
<version>6.0.26-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.3.22</validator_test_case_version>
|
||||
<validator_test_case_version>1.3.25</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>
|
||||
|
@ -705,6 +705,11 @@
|
|||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<configuration>
|
||||
<suppressionFiles>
|
||||
<suppressionFile>owasp-suppression-file.xml</suppressionFile>
|
||||
</suppressionFiles>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
|
|
Loading…
Reference in New Issue