From 52db200d8b0864c1ed36cac8949875a87176fe30 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 17 May 2023 10:32:43 +1000 Subject: [PATCH] change constraints on Reference targets for logical models --- .../type/StructureDefinitionValidator.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java index dbd12284a..e7245bbcf 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java @@ -19,6 +19,8 @@ import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; +import org.hl7.fhir.r5.extensions.ExtensionConstants; +import org.hl7.fhir.r5.extensions.Extensions; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Coding; @@ -125,11 +127,12 @@ public class StructureDefinitionValidator extends BaseValidator { } List differentials = src.getChildrenByName("differential"); List snapshots = src.getChildrenByName("snapshot"); + boolean logical = "logical".equals(src.getNamedChildValue("kind")); for (Element differential : differentials) { - ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName) && ok; + ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical) && ok; } for (Element snapshot : snapshots) { - ok = validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd, typeName) && ok; + ok = validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd, typeName, logical) && ok; } return ok; } @@ -169,18 +172,18 @@ public class StructureDefinitionValidator extends BaseValidator { } } - private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName) { + private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical) { boolean ok = true; List elements = elementList.getChildrenByName("element"); int cc = 0; for (Element element : elements) { - ok = validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName) && ok; + ok = validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName, logical) && ok; cc++; } return ok; } - private boolean validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName) { + private boolean validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical) { boolean ok = true; boolean typeMustSupport = false; String path = element.getNamedChildValue("path"); @@ -231,7 +234,7 @@ public class StructureDefinitionValidator extends BaseValidator { } // check the stated profile - must be a constraint on the type if (snapshot || sd != null) { - ok = validateElementType(errors, type, stack.push(type, -1, null, null), sd, path) && ok; + ok = validateElementType(errors, type, stack.push(type, -1, null, null), sd, path, logical) && ok; } } } @@ -479,7 +482,7 @@ public class StructureDefinitionValidator extends BaseValidator { return vr.getErrorClass() == null; } - private boolean validateElementType(List errors, Element type, NodeStack stack, StructureDefinition sd, String path) { + private boolean validateElementType(List errors, Element type, NodeStack stack, StructureDefinition sd, String path, boolean logical) { boolean ok = true; String code = type.getNamedChildValue("code"); if (code == null && path != null) { @@ -498,7 +501,7 @@ public class StructureDefinitionValidator extends BaseValidator { } profiles = type.getChildrenByName("targetProfile"); for (Element profile : profiles) { - ok = validateTargetProfile(errors, profile, code, stack.push(profile, -1, null, null), path) && ok; + ok = validateTargetProfile(errors, profile, code, stack.push(profile, -1, null, null), path, logical) && ok; } } } @@ -589,7 +592,7 @@ public class StructureDefinitionValidator extends BaseValidator { return t.getSnapshot().getElementFirstRep().getIsModifier(); } - private boolean validateTargetProfile(List errors, Element profile, String code, NodeStack stack, String path) { + private boolean validateTargetProfile(List errors, Element profile, String code, NodeStack stack, String path, boolean logical) { boolean ok = true; String p = profile.primitiveValue(); StructureDefinition sd = context.fetchResource(StructureDefinition.class, p); @@ -599,7 +602,7 @@ public class StructureDefinitionValidator extends BaseValidator { if (t == null) { ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p) && ok; } else { - ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), sd.getKind() == StructureDefinitionKind.RESOURCE, I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Resource") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), (sd.getKind() == StructureDefinitionKind.RESOURCE) || (logical && isReferenceableTarget(t)), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Resource") && ok; } } } else if (code.equals("canonical")) { @@ -619,6 +622,21 @@ public class StructureDefinitionValidator extends BaseValidator { return ok; } + private boolean isReferenceableTarget(StructureDefinition t) { + for (Extension ext : t.getExtensionsByUrl(ExtensionConstants.EXT_SDTYPE_CHARACTERISTICS)) { + if (ext.hasValue()) { + String c = ext.getValue().primitiveValue(); + if ("can-be-target".equals(c)) { + return true; + } + } + } + if (ToolingExtensions.readBoolExtension(t, "http://hl7.org/fhir/tools/StructureDefinition/logical-target")) { + return true; + } + return false; + } + private boolean isInstanceOf(StructureDefinition sd, String code) { while (sd != null) { if (sd.getType().equals(code)) {