various improvements to structure map validation
This commit is contained in:
parent
364a2aeec4
commit
808d4619d6
|
@ -195,6 +195,7 @@ import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.Utilities.DecimalStatus;
|
import org.hl7.fhir.utilities.Utilities.DecimalStatus;
|
||||||
import org.hl7.fhir.utilities.VersionUtilities;
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||||
|
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||||
import org.hl7.fhir.utilities.validation.IDigitalSignatureServices;
|
import org.hl7.fhir.utilities.validation.IDigitalSignatureServices;
|
||||||
|
@ -3810,7 +3811,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
size = cnt.length;
|
size = cnt.length;
|
||||||
}
|
}
|
||||||
} else if (url.startsWith("file:")) {
|
} else if (url.startsWith("file:")) {
|
||||||
size = new File(url.substring(5)).length();
|
size = ManagedFileAccess.file(url.substring(5)).length();
|
||||||
} else {
|
} else {
|
||||||
fetchError = context.formatMessage(I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_UNKNOWN_URL_SCHEME, url); }
|
fetchError = context.formatMessage(I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_UNKNOWN_URL_SCHEME, url); }
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -5699,7 +5700,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
} else if (element.getType().equals("StructureDefinition")) {
|
} else if (element.getType().equals("StructureDefinition")) {
|
||||||
return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack) && ok;
|
return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack) && ok;
|
||||||
} else if (element.getType().equals("StructureMap")) {
|
} else if (element.getType().equals("StructureMap")) {
|
||||||
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack) && ok;
|
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(valContext, errors, element, stack) && ok;
|
||||||
} else if (element.getType().equals("ValueSet")) {
|
} else if (element.getType().equals("ValueSet")) {
|
||||||
return new ValueSetValidator(this).validateValueSet(valContext, errors, element, stack) && ok;
|
return new ValueSetValidator(this).validateValueSet(valContext, errors, element, stack) && ok;
|
||||||
} else if ("http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition".equals(element.getProperty().getStructure().getUrl())) {
|
} else if ("http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition".equals(element.getProperty().getStructure().getUrl())) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.hl7.fhir.validation.instance.type;
|
package org.hl7.fhir.validation.instance.type;
|
||||||
|
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -30,6 +31,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
||||||
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
||||||
import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup;
|
import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup;
|
||||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.VersionUtilities;
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
|
@ -38,6 +40,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||||
import org.hl7.fhir.validation.BaseValidator;
|
import org.hl7.fhir.validation.BaseValidator;
|
||||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||||
|
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||||
|
|
||||||
public class StructureMapValidator extends BaseValidator {
|
public class StructureMapValidator extends BaseValidator {
|
||||||
|
|
||||||
|
@ -198,6 +201,20 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
return summary();
|
return summary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return VersionUtilities.getNameForVersion(sd.getFhirVersion().toCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sdSummary() {
|
||||||
|
if (sd == null) {
|
||||||
|
return "null";
|
||||||
|
} else if (!sd.hasUrl()) {
|
||||||
|
return "??";
|
||||||
|
} else {
|
||||||
|
return sd.getVersionedUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VariableSet {
|
public class VariableSet {
|
||||||
|
@ -313,7 +330,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateStructureMap(List<ValidationMessage> errors, Element src, NodeStack stack) {
|
public boolean validateStructureMap(ValidationContext valContext, List<ValidationMessage> errors, Element src, NodeStack stack) {
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
List<Element> imports = src.getChildrenByName("import");
|
List<Element> imports = src.getChildrenByName("import");
|
||||||
int cc = 0;
|
int cc = 0;
|
||||||
|
@ -334,7 +351,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
if (hasInputTypes(group) || group.hasUserData("structuremap.parameters")) {
|
if (hasInputTypes(group) || group.hasUserData("structuremap.parameters")) {
|
||||||
group.setUserData("structuremap.validated", true);
|
group.setUserData("structuremap.validated", true);
|
||||||
fired = true;
|
fired = true;
|
||||||
ok = validateGroup(errors, src, group, stack.push(group, cc, null, null), grpNames) && ok;
|
ok = validateGroup(valContext, errors, src, group, stack.push(group, cc, null, null), grpNames) && ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cc++;
|
cc++;
|
||||||
|
@ -345,7 +362,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
for (Element group : groups) {
|
for (Element group : groups) {
|
||||||
if (!group.hasUserData("structuremap.validated")) {
|
if (!group.hasUserData("structuremap.validated")) {
|
||||||
hint(errors, "2023-03-01", IssueType.INFORMATIONAL, group.line(), group.col(), stack.push(group, cc, null, null).getLiteralPath(), ok, I18nConstants.SM_ORPHAN_GROUP, group.getChildValue("name"));
|
hint(errors, "2023-03-01", IssueType.INFORMATIONAL, group.line(), group.col(), stack.push(group, cc, null, null).getLiteralPath(), ok, I18nConstants.SM_ORPHAN_GROUP, group.getChildValue("name"));
|
||||||
ok = validateGroup(errors, src, group, stack.push(group, cc, null, null), grpNames) && ok;
|
ok = validateGroup(valContext, errors, src, group, stack.push(group, cc, null, null), grpNames) && ok;
|
||||||
}
|
}
|
||||||
cc++;
|
cc++;
|
||||||
}
|
}
|
||||||
|
@ -378,7 +395,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateGroup(List<ValidationMessage> errors, Element src, Element group, NodeStack stack, List<String> grpNames) {
|
private boolean validateGroup(ValidationContext valContext, List<ValidationMessage> errors, Element src, Element group, NodeStack stack, List<String> grpNames) {
|
||||||
String name = group.getChildValue("name");
|
String name = group.getChildValue("name");
|
||||||
boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name);
|
boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name);
|
||||||
if (!rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), !grpNames.contains(name), I18nConstants.SM_GROUP_NAME_DUPLICATE, name)) {
|
if (!rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), !grpNames.contains(name), I18nConstants.SM_GROUP_NAME_DUPLICATE, name)) {
|
||||||
|
@ -403,7 +420,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
List<Element> structures = src.getChildrenByName("structure");
|
List<Element> structures = src.getChildrenByName("structure");
|
||||||
int cc = 0;
|
int cc = 0;
|
||||||
for (Element input : inputs) {
|
for (Element input : inputs) {
|
||||||
ok = validateInput(errors, src, group, input, stack.push(input, cc, null, null), structures, variables, pvars) && ok;
|
ok = validateInput(valContext, errors, src, group, input, stack.push(input, cc, null, null), structures, variables, pvars) && ok;
|
||||||
cc++;
|
cc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,7 +474,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
return grp;
|
return grp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateInput(List<ValidationMessage> errors, Element src, Element group, Element input, NodeStack stack, List<Element> structures, VariableSet variables, VariableSet pvars) {
|
private boolean validateInput(ValidationContext valContext, List<ValidationMessage> errors, Element src, Element group, Element input, NodeStack stack, List<Element> structures, VariableSet variables, VariableSet pvars) {
|
||||||
boolean ok = false;
|
boolean ok = false;
|
||||||
String gname = group.getChildValue("name");
|
String gname = group.getChildValue("name");
|
||||||
String name = input.getChildValue("name");
|
String name = input.getChildValue("name");
|
||||||
|
@ -493,8 +510,15 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
smode = structure.getChildValue("mode");
|
smode = structure.getChildValue("mode");
|
||||||
String url = structure.getChildValue("url");
|
String url = structure.getChildValue("url");
|
||||||
sd = context.fetchResource(StructureDefinition.class, url);
|
sd = context.fetchResource(StructureDefinition.class, url);
|
||||||
|
if (sd == null) {
|
||||||
|
try {
|
||||||
|
sd = (StructureDefinition) fetcher.fetchCanonicalResource((IResourceValidator) parent, valContext.getAppContext(), url);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// nothing?
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sd == null) {
|
if (sd == null) {
|
||||||
rule(errors, "2023-03-01", IssueType.INVALID, input.line(), input.col(), stack.getLiteralPath(), sd != null, I18nConstants.SM_GROUP_INPUT_TYPE_UNKNOWN_STRUCTURE, type, url);
|
warning(errors, "2023-03-01", IssueType.INVALID, input.line(), input.col(), stack.getLiteralPath(), sd != null, I18nConstants.SM_GROUP_INPUT_TYPE_UNKNOWN_STRUCTURE, type, url);
|
||||||
}
|
}
|
||||||
} else if (type != null) {
|
} else if (type != null) {
|
||||||
sd = context.fetchTypeDefinition(type);
|
sd = context.fetchTypeDefinition(type);
|
||||||
|
@ -895,7 +919,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
if (srcED != null) {
|
if (srcED != null) {
|
||||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, srcED.getBinding().hasValueSet() && srcED.getBinding().getStrength() == BindingStrength.REQUIRED, I18nConstants.SM_TARGET_TRANSLATE_BINDING_SOURCE)) {
|
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, srcED.getBinding().hasValueSet() && srcED.getBinding().getStrength() == BindingStrength.REQUIRED, I18nConstants.SM_TARGET_TRANSLATE_BINDING_SOURCE)) {
|
||||||
srcVS = context.findTxResource(ValueSet.class, srcED.getBinding().getValueSet());
|
srcVS = context.findTxResource(ValueSet.class, srcED.getBinding().getValueSet());
|
||||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, srcVS != null, I18nConstants.SM_TARGET_TRANSLATE_BINDING_VS_SOURCE)) {
|
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, srcVS != null, I18nConstants.SM_TARGET_TRANSLATE_BINDING_VS_SOURCE, srcED.getBinding().getValueSet())) {
|
||||||
ValueSetExpansionOutcome vse = context.expandVS(srcVS, true, false);
|
ValueSetExpansionOutcome vse = context.expandVS(srcVS, true, false);
|
||||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vse.isOk(), I18nConstants.SM_TARGET_TRANSLATE_BINDING_VSE_SOURCE, vse.getError())) {
|
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vse.isOk(), I18nConstants.SM_TARGET_TRANSLATE_BINDING_VSE_SOURCE, vse.getError())) {
|
||||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||||
|
@ -914,7 +938,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
if (srcED != null) {
|
if (srcED != null) {
|
||||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, tgtED.getBinding().hasValueSet() && tgtED.getBinding().getStrength() == BindingStrength.REQUIRED, I18nConstants.SM_TARGET_TRANSLATE_BINDING_TARGET)) {
|
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, tgtED.getBinding().hasValueSet() && tgtED.getBinding().getStrength() == BindingStrength.REQUIRED, I18nConstants.SM_TARGET_TRANSLATE_BINDING_TARGET)) {
|
||||||
ValueSet vs = context.findTxResource(ValueSet.class, tgtED.getBinding().getValueSet());
|
ValueSet vs = context.findTxResource(ValueSet.class, tgtED.getBinding().getValueSet());
|
||||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vs != null, I18nConstants.SM_TARGET_TRANSLATE_BINDING_VS_TARGET)) {
|
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vs != null, I18nConstants.SM_TARGET_TRANSLATE_BINDING_VS_TARGET, tgtED.getBinding().getValueSet())) {
|
||||||
ValueSetExpansionOutcome vse = context.expandVS(vs, true, false);
|
ValueSetExpansionOutcome vse = context.expandVS(vs, true, false);
|
||||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vse.isOk(), I18nConstants.SM_TARGET_TRANSLATE_BINDING_VSE_TARGET, vse.getError())) {
|
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vse.isOk(), I18nConstants.SM_TARGET_TRANSLATE_BINDING_VSE_TARGET, vse.getError())) {
|
||||||
List<String> systems = new ArrayList<>();
|
List<String> systems = new ArrayList<>();
|
||||||
|
@ -1065,6 +1089,9 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
throw new Error("Unable to resolve "+url);
|
throw new Error("Unable to resolve "+url);
|
||||||
} else {
|
} else {
|
||||||
ElementDefinition t2 = sdt.getSnapshot().getElementByPath(path);
|
ElementDefinition t2 = sdt.getSnapshot().getElementByPath(path);
|
||||||
|
if (t2 == null) {
|
||||||
|
t2 = sdt.getSnapshot().getElementById(path);
|
||||||
|
}
|
||||||
if (t2 == null) {
|
if (t2 == null) {
|
||||||
throw new Error("Unable to resolve "+path+" in "+url);
|
throw new Error("Unable to resolve "+path+" in "+url);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1128,8 +1155,9 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
String tgtType = tgtVar.getWorkingType();
|
String tgtType = tgtVar.getWorkingType();
|
||||||
if (rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), srcType != null, I18nConstants.SM_SOURCE_TYPE_NOT_FOUND) &&
|
if (rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), srcType != null, I18nConstants.SM_SOURCE_TYPE_NOT_FOUND) &&
|
||||||
rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), tgtType != null, I18nConstants.SM_TARGET_TYPE_NOT_FOUND)) {
|
rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), tgtType != null, I18nConstants.SM_TARGET_TYPE_NOT_FOUND)) {
|
||||||
StructureMapGroupComponent grp = findDefaultGroup(src, srcType, tgtType);
|
StructureMapGroupComponent grp = findDefaultGroup(src, srcType, srcVar.sd.getUrl(), tgtType, tgtVar.sd.getUrl());
|
||||||
ok = rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), grp != null, I18nConstants.SM_MATCHING_RULEGROUP_NOT_FOUND, srcType, tgtType) && ok;
|
ok = rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), grp != null, I18nConstants.SM_MATCHING_RULEGROUP_NOT_FOUND,
|
||||||
|
srcType+" ("+srcVar.sdSummary()+")", tgtType+" ("+tgtVar.sdSummary()+")") && ok;
|
||||||
} else {
|
} else {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
@ -1213,7 +1241,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureMapGroupComponent findDefaultGroup(Element src, String srcType, String tgtType) {
|
private StructureMapGroupComponent findDefaultGroup(Element src, String srcType, String srcUrl, String tgtType, String tgtUrl) {
|
||||||
List<Element> groups = src.getChildrenByName("group");
|
List<Element> groups = src.getChildrenByName("group");
|
||||||
for (Element group : groups) {
|
for (Element group : groups) {
|
||||||
if (Utilities.existsInList(group.getChildValue("typeMode"), "types", "type-and-types")) {
|
if (Utilities.existsInList(group.getChildValue("typeMode"), "types", "type-and-types")) {
|
||||||
|
@ -1221,7 +1249,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
if (inputs.size() == 2 && "source".equals(inputs.get(0).getChildValue("mode")) && "source".equals(inputs.get(0).getChildValue("mode"))) {
|
if (inputs.size() == 2 && "source".equals(inputs.get(0).getChildValue("mode")) && "source".equals(inputs.get(0).getChildValue("mode"))) {
|
||||||
String srcT = resolveInputType(src, inputs.get(0));
|
String srcT = resolveInputType(src, inputs.get(0));
|
||||||
String tgtT = resolveInputType(src, inputs.get(1));
|
String tgtT = resolveInputType(src, inputs.get(1));
|
||||||
if (sameTypes(srcT, srcType) && sameTypes(tgtT, tgtType)) {
|
if (sameTypes(srcT, srcType) && sameTypes(tgtT, tgtType) || sameTypes(srcT, srcUrl) && sameTypes(tgtT, tgtUrl)) {
|
||||||
return makeGroupComponent(group);
|
return makeGroupComponent(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1233,7 +1261,7 @@ public class StructureMapValidator extends BaseValidator {
|
||||||
grp.getInput().size() == 2 && grp.getInput().get(0).getMode() == StructureMapInputMode.SOURCE && grp.getInput().get(1).getMode() == StructureMapInputMode.TARGET) {
|
grp.getInput().size() == 2 && grp.getInput().get(0).getMode() == StructureMapInputMode.SOURCE && grp.getInput().get(1).getMode() == StructureMapInputMode.TARGET) {
|
||||||
String srcT = resolveInputType(map, grp.getInput().get(0));
|
String srcT = resolveInputType(map, grp.getInput().get(0));
|
||||||
String tgtT = resolveInputType(map, grp.getInput().get(1));
|
String tgtT = resolveInputType(map, grp.getInput().get(1));
|
||||||
if (sameTypes(srcT, srcType) && sameTypes(tgtT, tgtType)) {
|
if (sameTypes(srcT, srcType) && sameTypes(tgtT, tgtType) || sameTypes(srcT, srcUrl) && sameTypes(tgtT, tgtUrl)) {
|
||||||
return grp;
|
return grp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue