fix validation of profiles and target profiles in all versions (before R3 different rules)

This commit is contained in:
Grahame Grieve 2020-12-03 16:57:53 +11:00
parent 36dae96eef
commit 7d95b27c1f
4 changed files with 80 additions and 5 deletions

View File

@ -455,4 +455,12 @@ public class VersionUtilities {
return res;
}
public static String getVersionForPackage(String pid) {
if (pid.startsWith("hl7.fhir.r")) {
String[] p = pid.split("\\.");
return versionFromCode(p[2]);
}
return null;
}
}

View File

@ -350,6 +350,7 @@ public class I18nConstants {
public static final String SD_ED_TYPE_PROFILE_UNKNOWN = "SD_ED_TYPE_PROFILE_UNKNOWN";
public static final String SD_ED_TYPE_PROFILE_NOTYPE = "SD_ED_TYPE_PROFILE_NOTYPE";
public static final String SD_ED_TYPE_PROFILE_WRONG = "SD_ED_TYPE_PROFILE_WRONG";
public static final String SD_ED_TYPE_NO_TARGET_PROFILE = "SD_ED_TYPE_NO_TARGET_PROFILE";
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";

View File

@ -618,7 +618,8 @@ SD_NESTED_MUST_SUPPORT_SNAPSHOT = The element {0} has types/profiles/targets tha
Unable_to_connect_to_terminology_server = Unable to connect to terminology server. Error = {0}
SD_ED_TYPE_PROFILE_UNKNOWN = Unable to resolve profile {0}
SD_ED_TYPE_PROFILE_NOTYPE = Found profile {0}, but unable to determine the type it applies it
SD_ED_TYPE_PROFILE_WRONG = Profile {0} is for type {1}, but this element has type {2}
SD_ED_TYPE_PROFILE_WRONG = Profile {0} is for type {1}, but the {3} element has type {2}
SD_ED_TYPE_NO_TARGET_PROFILE = Type {0} does not allow for target Profiles
TERMINOLOGY_TX_NOSVC_BOUND_REQ = Could not confirm that the codes provided are from the required value set {0} because there is no terminology service
TERMINOLOGY_TX_NOSVC_BOUND_EXT = Could not confirm that the codes provided are from the extensible value set {0} because there is no terminology service
ARRAY_CANNOT_BE_EMPTY = Array cannot be empty - the property should not be present if it has no values

View File

@ -20,6 +20,7 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.ToolingExtensions;
@ -139,12 +140,50 @@ public class StructureDefinitionValidator extends BaseValidator {
}
if (code != null) {
List<Element> profiles = type.getChildrenByName("profile");
for (Element profile : profiles) {
validateTypeProfile(errors, profile, code, stack.push(type, -1, null, null));
if (VersionUtilities.isR2Ver(context.getVersion()) || VersionUtilities.isR2BVer(context.getVersion()) ) {
for (Element profile : profiles) {
validateProfileTypeOrTarget(errors, profile, code, stack.push(profile, -1, null, null), path);
}
} else {
for (Element profile : profiles) {
validateTypeProfile(errors, profile, code, stack.push(profile, -1, null, null), path);
}
profiles = type.getChildrenByName("targetProfile");
for (Element profile : profiles) {
validateTargetProfile(errors, profile, code, stack.push(profile, -1, null, null), path);
}
}
}
}
private void validateProfileTypeOrTarget(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path) {
String p = profile.primitiveValue();
StructureDefinition sd = context.fetchResource(StructureDefinition.class, p);
if (code.equals("Reference")) {
if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
String t = determineBaseType(sd);
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), code.equals(t), I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd.getKind() == StructureDefinitionKind.RESOURCE, I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path);
}
}
} else {
if (sd == null ) {
sd = getXverExt(errors, stack.getLiteralPath(), profile, p);
}
if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
String t = determineBaseType(sd);
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), code.equals(t), I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), isInstanceOf(t, code), I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path);
}
}
}
}
private String getTypeCodeFromSD(StructureDefinition sd, String path) {
ElementDefinition ed = null;
for (ElementDefinition t : sd.getSnapshot().getElement()) {
@ -159,7 +198,7 @@ public class StructureDefinitionValidator extends BaseValidator {
return ed != null && ed.getType().size() == 1 ? ed.getTypeFirstRep().getCode() : null;
}
private void validateTypeProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack) {
private void validateTypeProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path) {
String p = profile.primitiveValue();
StructureDefinition sd = context.fetchResource(StructureDefinition.class, p);
if (sd == null ) {
@ -170,11 +209,37 @@ public class StructureDefinitionValidator extends BaseValidator {
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), code.equals(t), I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), isInstanceOf(t, code), I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code);
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), isInstanceOf(t, code), I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path);
}
}
}
private void validateTargetProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path) {
String p = profile.primitiveValue();
StructureDefinition sd = context.fetchResource(StructureDefinition.class, p);
if (code.equals("Reference")) {
if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
String t = determineBaseType(sd);
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), code.equals(t), I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd.getKind() == StructureDefinitionKind.RESOURCE, I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path);
}
}
} else if (code.equals("canonical")) {
if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
String t = determineBaseType(sd);
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), code.equals(t), I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t), I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path);
}
}
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_NO_TARGET_PROFILE, code);
}
}
private boolean isInstanceOf(String t, String code) {
StructureDefinition sd = context.fetchTypeDefinition(t);
while (sd != null) {