Gg 202210 shareables (#936)

* Don't validate contained resources against Shareable* Profiles, + validate ShareableMeasure

* release notes

* fix compile problem

Co-authored-by: Grahame Grieve <grahameg@gmail.ccom>
This commit is contained in:
Grahame Grieve 2022-09-30 12:00:22 -07:00 committed by GitHub
parent eabf51938b
commit d71a5833c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 22 deletions

View File

@ -1,6 +1,7 @@
## Validator Changes ## Validator Changes
* Warning in Validator CLI when character encoding is not UTF-8 * Warning in Validator CLI when character encoding is not UTF-8
* Don't validate contained resources against Shareable* profiles, and also check ShareableMeasure
## Other code changes ## Other code changes

View File

@ -1,5 +1,6 @@
package org.hl7.fhir.convertors.misc; package org.hl7.fhir.convertors.misc;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -28,10 +29,10 @@ public class VSACImporter extends OIDBasedValueSetImporter {
public static void main(String[] args) throws FHIRException, IOException, ParseException, URISyntaxException { public static void main(String[] args) throws FHIRException, IOException, ParseException, URISyntaxException {
VSACImporter self = new VSACImporter(); VSACImporter self = new VSACImporter();
self.process(args[0], args[1], args[2]); self.process(args[0], args[1], args[2], "true".equals(args[3]));
} }
private void process(String source, String dest, String apiKey) throws FHIRException, IOException, URISyntaxException { private void process(String source, String dest, String apiKey, boolean onlyNew) throws FHIRException, IOException, URISyntaxException {
CSVReader csv = new CSVReader(new FileInputStream(source)); CSVReader csv = new CSVReader(new FileInputStream(source));
csv.readHeaders(); csv.readHeaders();
Map<String, String> errs = new HashMap<>(); Map<String, String> errs = new HashMap<>();
@ -39,23 +40,25 @@ public class VSACImporter extends OIDBasedValueSetImporter {
FHIRToolingClient fhirToolingClient = new FHIRToolingClient("https://cts.nlm.nih.gov/fhir", "fhir/vsac"); FHIRToolingClient fhirToolingClient = new FHIRToolingClient("https://cts.nlm.nih.gov/fhir", "fhir/vsac");
fhirToolingClient.setUsername("apikey"); fhirToolingClient.setUsername("apikey");
fhirToolingClient.setPassword(apiKey); fhirToolingClient.setPassword(apiKey);
fhirToolingClient.setTimeout(30000); fhirToolingClient.setTimeout(120000);
int i = 0; int i = 0;
int j = 0; int j = 0;
while (csv.line()) { while (csv.line()) {
String oid = csv.cell("OID"); String oid = csv.cell("OID");
try { try {
ValueSet vs = fhirToolingClient.read(ValueSet.class, oid); if (!onlyNew || !(new File(Utilities.path(dest, "ValueSet-" + oid + ".json")).exists())) {
try { ValueSet vs = fhirToolingClient.read(ValueSet.class, oid);
ValueSet vse = fhirToolingClient.expandValueset(vs.getUrl(), null); try {
vs.setExpansion(vse.getExpansion()); ValueSet vse = fhirToolingClient.expandValueset(vs.getUrl(), null);
j++; vs.setExpansion(vse.getExpansion());
} catch (Exception e) { j++;
errs.put(oid, "Expansion: " +e.getMessage()); } catch (Exception e) {
System.out.println(e.getMessage()); errs.put(oid, "Expansion: " +e.getMessage());
System.out.println(e.getMessage());
}
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "ValueSet-" + oid + ".json")), vs);
} }
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "ValueSet-" + oid + ".json")), vs);
i++; i++;
if (i % 100 == 0) { if (i % 100 == 0) {
System.out.println(":"+i+" ("+j+")"); System.out.println(":"+i+" ("+j+")");

View File

@ -635,6 +635,10 @@ public class I18nConstants {
public static final String CODESYSTEM_SHAREABLE_MISSING_HL7 = "CODESYSTEM_SHAREABLE_MISSING_HL7"; public static final String CODESYSTEM_SHAREABLE_MISSING_HL7 = "CODESYSTEM_SHAREABLE_MISSING_HL7";
public static final String CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7 = "CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7"; public static final String CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7 = "CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7";
public static final String CODESYSTEM_SHAREABLE_EXTRA_MISSING = "CODESYSTEM_SHAREABLE_EXTRA_MISSING"; public static final String CODESYSTEM_SHAREABLE_EXTRA_MISSING = "CODESYSTEM_SHAREABLE_EXTRA_MISSING";
public static final String MEASURE_SHAREABLE_MISSING = "MEASURE_SHAREABLE_MISSING";
public static final String MEASURE_SHAREABLE_MISSING_HL7 = "MEASURE_SHAREABLE_MISSING_HL7";
public static final String MEASURE_SHAREABLE_EXTRA_MISSING_HL7 = "MEASURE_SHAREABLE_EXTRA_MISSING_HL7";
public static final String MEASURE_SHAREABLE_EXTRA_MISSING = "MEASURE_SHAREABLE_EXTRA_MISSING";
public static final String VALUESET_UNC_SYSTEM_WARNING = "VALUESET_UNC_SYSTEM_WARNING"; public static final String VALUESET_UNC_SYSTEM_WARNING = "VALUESET_UNC_SYSTEM_WARNING";
public static final String VALUESET_UNC_SYSTEM_WARNING_VER = "VALUESET_UNC_SYSTEM_WARNING_VER"; public static final String VALUESET_UNC_SYSTEM_WARNING_VER = "VALUESET_UNC_SYSTEM_WARNING_VER";
public static final String VALUESET_IMPORT_UNION_INTERSECTION = "VALUESET_IMPORT_UNION_INTERSECTION"; public static final String VALUESET_IMPORT_UNION_INTERSECTION = "VALUESET_IMPORT_UNION_INTERSECTION";

View File

@ -726,7 +726,11 @@ VALUESET_SHAREABLE_MISSING = The ShareableValueSet profile says that the {0} ele
VALUESET_SHAREABLE_EXTRA_MISSING = The ShareableValueSet profile recommends that the {0} element is populated, but it is not present. Published value sets SHOULD conform to the ShareableValueSet profile VALUESET_SHAREABLE_EXTRA_MISSING = The ShareableValueSet profile recommends that the {0} element is populated, but it is not present. Published value sets SHOULD conform to the ShareableValueSet profile
VALUESET_SHAREABLE_MISSING_HL7 = The ShareableValueSet profile says that the {0} element is mandatory, but it is not found. HL7 Published value sets SHALL conform to the ShareableValueSet profile VALUESET_SHAREABLE_MISSING_HL7 = The ShareableValueSet profile says that the {0} element is mandatory, but it is not found. HL7 Published value sets SHALL conform to the ShareableValueSet profile
VALUESET_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableValueSet profile recommends that the {0} element is populated, but it is not found. HL7 Published value sets SHALL conform to the ShareableValueSet profile VALUESET_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableValueSet profile recommends that the {0} element is populated, but it is not found. HL7 Published value sets SHALL conform to the ShareableValueSet profile
CODESYSTEM_SHAREABLE_MISSING = The ShareableCodeSystem profile says that the {0} element is mandatory, but it is not present. Published value sets SHOULD conform to the ShareableCodeSystem profile CODESYSTEM_SHAREABLE_MISSING = The ShareableCodeSystem profile says that the {0} element is mandatory, but it is not present. Published code systems SHOULD conform to the ShareableCodeSystem profile
CODESYSTEM_SHAREABLE_EXTRA_MISSING = The ShareableCodeSystem profile recommends that the {0} element is populated, but it is not present. Published value sets SHOULD conform to the ShareableCodeSystem profile CODESYSTEM_SHAREABLE_EXTRA_MISSING = The ShareableCodeSystem profile recommends that the {0} element is populated, but it is not present. Published code systems SHOULD conform to the ShareableCodeSystem profile
CODESYSTEM_SHAREABLE_MISSING_HL7 = The ShareableCodeSystem profile says that the {0} element is mandatory, but it is not found. HL7 Published value sets SHALL conform to the ShareableCodeSystem profile CODESYSTEM_SHAREABLE_MISSING_HL7 = The ShareableCodeSystem profile says that the {0} element is mandatory, but it is not found. HL7 Published code systems SHALL conform to the ShareableCodeSystem profile
CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableCodeSystem profile recommends that the {0} element is populated, but it is not found. HL7 Published value sets SHALL conform to the ShareableCodeSystem profile CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableCodeSystem profile recommends that the {0} element is populated, but it is not found. HL7 Published code systems SHALL conform to the ShareableCodeSystem profile
MEASURE_SHAREABLE_MISSING = The ShareableMeasure profile says that the {0} element is mandatory, but it is not present. Published measures SHOULD conform to the ShareableMeasure profile
MEASURE_SHAREABLE_EXTRA_MISSING = The ShareableMeasure profile recommends that the {0} element is populated, but it is not present. Published measures SHOULD conform to the ShareableMeasure profile
MEASURE_SHAREABLE_MISSING_HL7 = The ShareableMeasure profile says that the {0} element is mandatory, but it is not found. HL7 Published measures SHALL conform to the ShareableMeasure profile
MEASURE_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableMeasure profile recommends that the {0} element is populated, but it is not found. HL7 Published measures SHALL conform to the ShareableMeasure profile

View File

@ -4638,9 +4638,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else if (element.getType().equals("QuestionnaireResponse")) { } else if (element.getType().equals("QuestionnaireResponse")) {
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager, jurisdiction).validateQuestionannaireResponse(hostContext, errors, element, stack); new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager, jurisdiction).validateQuestionannaireResponse(hostContext, errors, element, stack);
} else if (element.getType().equals("Measure")) { } else if (element.getType().equals("Measure")) {
new MeasureValidator(context, timeTracker, xverManager, jurisdiction).validateMeasure(hostContext, errors, element, stack); new MeasureValidator(context, timeTracker, xverManager, jurisdiction, this).validateMeasure(hostContext, errors, element, stack);
} else if (element.getType().equals("MeasureReport")) { } else if (element.getType().equals("MeasureReport")) {
new MeasureValidator(context, timeTracker, xverManager, jurisdiction).validateMeasureReport(hostContext, errors, element, stack); new MeasureValidator(context, timeTracker, xverManager, jurisdiction, this).validateMeasureReport(hostContext, errors, element, stack);
} else if (element.getType().equals("CapabilityStatement")) { } else if (element.getType().equals("CapabilityStatement")) {
validateCapabilityStatement(errors, element, stack); validateCapabilityStatement(errors, element, stack);
} else if (element.getType().equals("CodeSystem")) { } else if (element.getType().equals("CodeSystem")) {

View File

@ -84,7 +84,9 @@ public class CodeSystemValidator extends BaseValidator {
} }
} }
checkShareableCodeSystem(errors, cs, stack); if (!stack.isContained()) {
checkShareableCodeSystem(errors, cs, stack);
}
} }

View File

@ -37,17 +37,20 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.xml.XMLUtil; import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker; import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.instance.InstanceValidator;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
import org.w3c.dom.Document; import org.w3c.dom.Document;
public class MeasureValidator extends BaseValidator { public class MeasureValidator extends BaseValidator {
public MeasureValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager, Coding jurisdiction) { private InstanceValidator parent;
public MeasureValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager, Coding jurisdiction, InstanceValidator parent) {
super(context, xverManager); super(context, xverManager);
source = Source.InstanceValidator; source = Source.InstanceValidator;
this.timeTracker = timeTracker; this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction; this.jurisdiction = jurisdiction;
this.parent = parent;
} }
@ -105,8 +108,41 @@ public class MeasureValidator extends BaseValidator {
c++; c++;
} }
} }
if (!stack.isContained()) {
checkShareableMeasure(errors, element, stack);
}
} }
private void checkShareableMeasure(List<ValidationMessage> errors, Element cs, NodeStack stack) {
if (parent.isForPublication()) {
if (isHL7(cs)) {
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "url");
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "version");
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "title");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING_HL7, "name");
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "status");
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "experimental");
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "description");
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "content");
if (!"supplement".equals(cs.getChildValue("content"))) {
rule(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "caseSensitive");
}
} else {
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.MEASURE_SHAREABLE_MISSING, "url");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.MEASURE_SHAREABLE_MISSING, "version");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.MEASURE_SHAREABLE_MISSING, "title");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING, "name");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.MEASURE_SHAREABLE_MISSING, "status");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.MEASURE_SHAREABLE_MISSING, "experimental");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.MEASURE_SHAREABLE_MISSING, "description");
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content"), I18nConstants.MEASURE_SHAREABLE_MISSING, "content");
if (!"supplement".equals(cs.getChildValue("content"))) {
warning(errors, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive"), I18nConstants.MEASURE_SHAREABLE_MISSING, "caseSensitive");
}
}
}
}
private void validateMeasureCriteria(ValidatorHostContext hostContext, List<ValidationMessage> errors, MeasureContext mctxt, Element crit, NodeStack nsc) { private void validateMeasureCriteria(ValidatorHostContext hostContext, List<ValidationMessage> errors, MeasureContext mctxt, Element crit, NodeStack nsc) {
String mimeType = crit.getChildValue("language"); String mimeType = crit.getChildValue("language");
if (!Utilities.noString(mimeType)) { // that would be an error elsewhere if (!Utilities.noString(mimeType)) { // that would be an error elsewhere

View File

@ -115,8 +115,9 @@ public class StructureDefinitionValidator extends BaseValidator {
for (Element snapshot : snapshots) { for (Element snapshot : snapshots) {
validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd); validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd);
} }
} }
private void validateElementList(List<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) { private void validateElementList(List<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) {
List<Element> elements = elementList.getChildrenByName("element"); List<Element> elements = elementList.getChildrenByName("element");
int cc = 0; int cc = 0;

View File

@ -61,7 +61,9 @@ public class ValueSetValidator extends BaseValidator {
cc++; cc++;
} }
} }
checkShareableValueSet(errors, vs, stack); if (!stack.isContained()) {
checkShareableValueSet(errors, vs, stack);
}
} }
private void checkShareableValueSet(List<ValidationMessage> errors, Element vs, NodeStack stack) { private void checkShareableValueSet(List<ValidationMessage> errors, Element vs, NodeStack stack) {