From 2519858dcd189aa5edeaf4583b72bc242ea50853 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 3 Nov 2022 15:59:22 +1100 Subject: [PATCH 1/2] update logical model snapshot generation and validation --- .../fhir/r5/conformance/ProfileUtilities.java | 53 ++++++++----------- .../fhir/r5/model/StructureDefinition.java | 7 +++ .../fhir/utilities/i18n/I18nConstants.java | 9 ++++ .../src/main/resources/Messages.properties | 9 ++++ .../instance/InstanceValidator.java | 41 +++++++++++++- .../type/StructureDefinitionValidator.java | 30 +++++++---- 6 files changed, 107 insertions(+), 42 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 2d1c792bb..dae92ab1c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -691,7 +691,7 @@ public class ProfileUtilities extends TranslatingUtilities { derived.setSnapshot(new StructureDefinitionSnapshotComponent()); try { - checkDifferential(derived.getDifferential().getElement(), typeName(derived.getType()), derived.getUrl()); + checkDifferential(derived.getDifferential().getElement(), derived.getTypeName(), derived.getUrl()); checkDifferentialBaseType(derived); copyInheritedExtensions(base, derived); @@ -712,11 +712,9 @@ public class ProfileUtilities extends TranslatingUtilities { StructureDefinitionDifferentialComponent diff = cloneDiff(derived.getDifferential()); // we make a copy here because we're sometimes going to hack the differential while processing it. Have to migrate user data back afterwards StructureDefinitionSnapshotComponent baseSnapshot = base.getSnapshot(); if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { - String derivedType = derived.getType(); - if (StructureDefinitionKind.LOGICAL.equals(derived.getKind()) && derived.getType().contains("/")) { - derivedType = derivedType.substring(derivedType.lastIndexOf("/")+1); - } - baseSnapshot = cloneSnapshot(baseSnapshot, base.getType(), derivedType); + String derivedType = derived.getTypeName(); + + baseSnapshot = cloneSnapshot(baseSnapshot, base.getTypeName(), derivedType); } // if (derived.getId().equals("2.16.840.1.113883.10.20.22.2.1.1")) { // debug = true; @@ -726,7 +724,7 @@ public class ProfileUtilities extends TranslatingUtilities { checkGroupConstraints(derived); if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { for (ElementDefinition e : diff.getElement()) { - if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) { + if (!e.hasUserData(GENERATED_IN_SNAPSHOT) && e.getPath().contains(".")) { ElementDefinition outcome = updateURLs(url, webUrl, e.copy()); e.setUserData(GENERATED_IN_SNAPSHOT, outcome); derived.getSnapshot().addElement(outcome); @@ -878,11 +876,11 @@ public class ProfileUtilities extends TranslatingUtilities { private void addInheritedElementsForSpecialization(StructureDefinitionSnapshotComponent snapshot, ElementDefinition focus, String type, String path, String url, String weburl) { StructureDefinition sd = context.fetchTypeDefinition(type); if (sd != null) { - addInheritedElementsForSpecialization(snapshot, focus, sd.getBaseDefinition(), path, url, weburl); + // don't do this. should already be in snapshot ... addInheritedElementsForSpecialization(snapshot, focus, sd.getBaseDefinition(), path, url, weburl); for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().contains(".")) { ElementDefinition outcome = updateURLs(url, weburl, ed.copy()); - outcome.setPath(outcome.getPath().replace(sd.getType(), path)); + outcome.setPath(outcome.getPath().replace(sd.getTypeName(), path)); snapshot.getElement().add(outcome); } else { focus.getConstraint().addAll(ed.getConstraint()); @@ -935,13 +933,6 @@ public class ProfileUtilities extends TranslatingUtilities { return sd != null && type.size() == 1 && sd.getType().equals(type.get(0).getCode()); } - private String typeName(String type) { - if (Utilities.isAbsoluteUrl(type)) { - return type.substring(type.lastIndexOf("/")+1); - } else { - return type; - } - } private void checkGroupConstraints(StructureDefinition derived) { List toRemove = new ArrayList<>(); @@ -3722,7 +3713,7 @@ public class ProfileUtilities extends TranslatingUtilities { c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), tail(ed.getElement().getPath()), ed.getElement().getPath())); } else { c.getPieces().add(gen.new Piece(null, translate("sd.table", "See ", ed.getElement().getPath()), null)); - c.getPieces().add(gen.new Piece(pfx(corePath, ed.getSource().getUserString("path"))+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getType()+")", ed.getElement().getPath())); + c.getPieces().add(gen.new Piece(pfx(corePath, ed.getSource().getUserString("path"))+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getTypeName()+")", ed.getElement().getPath())); } } return c; @@ -3842,7 +3833,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (sd == null) { c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); } else { - c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getType(), null))); + c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getTypeName(), null))); } } else if (pkp != null && pkp.hasLinkFor(tc)) { c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); @@ -4118,13 +4109,13 @@ public class ProfileUtilities extends TranslatingUtilities { List list = new ArrayList<>(); list.addAll(profile.getDifferential().getElement()); if (list.isEmpty()) { - ElementDefinition root = new ElementDefinition().setPath(profile.getType()); - root.setId(profile.getType()); + ElementDefinition root = new ElementDefinition().setPath(profile.getTypeName()); + root.setId(profile.getTypeName()); list.add(root); } else { if (list.get(0).getPath().contains(".")) { - ElementDefinition root = new ElementDefinition().setPath(profile.getType()); - root.setId(profile.getType()); + ElementDefinition root = new ElementDefinition().setPath(profile.getTypeName()); + root.setId(profile.getTypeName()); list.add(0, root); } } @@ -4652,7 +4643,7 @@ public class ProfileUtilities extends TranslatingUtilities { choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); - Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null); + Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getTypeName(), null, null); choicerow.getCells().add(c); if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { c.addPiece(gen.new Piece(null, " ", null)); @@ -4663,7 +4654,7 @@ public class ProfileUtilities extends TranslatingUtilities { choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); - Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null); + Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getTypeName(), null, null); choicerow.getCells().add(c); if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { c.addPiece(gen.new Piece(null, " ", null)); @@ -4879,7 +4870,7 @@ public class ProfileUtilities extends TranslatingUtilities { boolean first = true; for (StructureDefinition sd : children) { if (first) first = false; else c.addPiece(gen.new Piece(null, ", ", null)); - c.addPiece(gen.new Piece(sd.getUserString("path"), sd.getType(), null)); + c.addPiece(gen.new Piece(sd.getUserString("path"), sd.getTypeName(), null)); } } } @@ -5052,7 +5043,7 @@ public class ProfileUtilities extends TranslatingUtilities { c.getPieces().add(gen.new Piece(null, type, null)); c.getPieces().add(gen.new Piece("")); } else { - c.getPieces().add(gen.new Piece(sd.getUserString("path"), sd.getType(), null)); + c.getPieces().add(gen.new Piece(sd.getUserString("path"), sd.getTypeName(), null)); } } } @@ -5332,7 +5323,7 @@ public class ProfileUtilities extends TranslatingUtilities { private ElementDefinition findElementDefinition(StructureDefinition sd, String name) { - String path = sd.getType()+"."+name; + String path = sd.getTypeName()+"."+name; for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().equals(path)) return ed; @@ -5403,7 +5394,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (ed.getSource() == profile) { c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), "See "+ed.getElement().getPath(), null)); } else { - c.getPieces().add(gen.new Piece(ed.getSource().getUserData("path")+"#"+ed.getElement().getPath(), "See "+ed.getSource().getType()+"."+ed.getElement().getPath(), null)); + c.getPieces().add(gen.new Piece(ed.getSource().getUserData("path")+"#"+ed.getElement().getPath(), "See "+ed.getSource().getTypeName()+"."+ed.getElement().getPath(), null)); } } } @@ -5618,7 +5609,7 @@ public class ProfileUtilities extends TranslatingUtilities { private String baseType(String value) { StructureDefinition sd = context.fetchTypeDefinition(value); if (sd != null) // might be running before all SDs are available - return sd.getType(); + return sd.getTypeName(); if (Utilities.existsInList(value, "SimpleQuantity", "MoneyQuantity")) return "Quantity"; throw new Error(context.formatMessage(I18nConstants.INTERNAL_ERROR___TYPE_NOT_KNOWN_, value)); @@ -6736,7 +6727,7 @@ public class ProfileUtilities extends TranslatingUtilities { res.setName(name); res.setCardinality(cardinality); res.setProfileLink(profile.getUserString("path")); - res.setResType(profile.getType()); + res.setResType(profile.getTypeName()); StructureDefinition base = context.fetchResource(StructureDefinition.class, res.getResType()); if (base != null) res.setResLink(base.getUserString("path")); @@ -7163,7 +7154,7 @@ public class ProfileUtilities extends TranslatingUtilities { b.append(""); - b.append(Utilities.escapeXml(sd.getType())); + b.append(Utilities.escapeXml(sd.getTypeName())); b.append(""); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java index 19bb2ef99..a1c132799 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java @@ -4671,7 +4671,14 @@ public String describeType() { return "Definition"; } } + +public String getTypeName() { + String t = getType(); + return StructureDefinitionKind.LOGICAL.equals(getKind()) && t.contains("/") ? t.substring(t.lastIndexOf("/")+1) : t; +} + // end addition + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index 862089f86..53bc9e2a7 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -739,6 +739,15 @@ public class I18nConstants { public static final String TYPE_SPECIFIER_NM_ILLEGAL_TYPE = "TYPE_SPECIFIER_NM_ILLEGAL_TYPE"; public static final String TYPE_SPECIFIER_NM_ABSTRACT_TYPE = "TYPE_SPECIFIER_NM_ABSTRACT_TYPE"; public static final String Bundle_BUNDLE_Entry_NO_LOGICAL_EXPL = "Bundle_BUNDLE_Entry_NO_LOGICAL_EXPL"; + public static final String SD_TYPE_MISSING = "SD_TYPE_MISSING"; + public static final String SD_TYPE_NOT_MATCH_NS = "SD_TYPE_NOT_MATCH_NS"; + public static final String SD_TYPE_NOT_DERIVED = "SD_TYPE_NOT_DERIVED"; + public static final String SD_TYPE_NOT_LOCAL = "SD_TYPE_NOT_LOCAL"; + public static final String SD_TYPE_NOT_LOGICAL = "SD_TYPE_NOT_LOGICAL"; + public static final String SD_CONSTRAINED_TYPE_NO_MATCH = "SD_CONSTRAINED_TYPE_NO_MATCH"; + public static final String SD_SPECIALIZED_TYPE_MATCHES = "SD_SPECIALIZED_TYPE_MATCHES"; + public static final String SD_CONSTRAINED_KIND_NO_MATCH = "SD_CONSTRAINED_KIND_NO_MATCH"; + public static final String SD_PATH_TYPE_MISMATCH = "SD_PATH_TYPE_MISMATCH"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 86f379fb3..e0c2a4d59 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -755,3 +755,12 @@ ELEMENT_CANNOT_BE_NULL = The element is not allowed to be 'null' MULTIPLE_LOGICAL_MODELS_PLURAL={0} Logical Models found in supplied profiles, so unable to parse logical model (can only be one, found {1}) UNRECOGNISED_PROPERTY_TYPE = Invalid JSON type {0} for the element {1}; valid types = {2} UNRECOGNISED_PROPERTY_TYPE_WRONG = Invalid type {2} for the element {1}; valid types = {3}, JSON type = {0} +SD_TYPE_MISSING = No type found +SD_TYPE_NOT_MATCH_NS = The type namespace {0} SHOULD match the url namespace {1} for the definition of the type +SD_TYPE_NOT_DERIVED = The type {0} can only be used as a type when constraining the base definition of the type +SD_TYPE_NOT_LOCAL = The type {0} is not legal because it is not defined in the FHIR specification. Other types must have a namespace on them +SD_TYPE_NOT_LOGICAL = The type {0} can only be defined if the kind is 'logical' not {1} +SD_CONSTRAINED_TYPE_NO_MATCH = The type {0} must be the same as the type in the base structure {1} that is being constrained +SD_SPECIALIZED_TYPE_MATCHES = The type {0} must not be the same as the type in the base structure {1} that is being specialised +SD_CONSTRAINED_KIND_NO_MATCH = The kind {0} must be the same as the kind {1} in the base structure {2} +SD_PATH_TYPE_MISMATCH = The path {1} must start with the type of the structure {0} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 03860f556..b1691f39b 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -2457,7 +2457,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } if (context.hasBinding() && e.primitiveValue() != null) { - ok = checkPrimitiveBinding(hostContext, errors, path, type, context, e, profile, node) && ok; + // special cases + if ("StructureDefinition.type".equals(context.getPath()) && "http://hl7.org/fhir/StructureDefinition/StructureDefinition".equals(profile.getUrl())) { + ok = checkTypeValue(errors, path, e, node.getElement()); + } else { + ok = checkPrimitiveBinding(hostContext, errors, path, type, context, e, profile, node) && ok; + } } if (type.equals("markdown") && htmlInMarkdownCheck != HtmlInMarkdownCheck.NONE) { @@ -2501,6 +2506,40 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } + private boolean checkTypeValue(List errors, String path, Element e, Element sd) { + String v = e.primitiveValue(); + if (v == null) { + return rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.SD_TYPE_MISSING); + } + String url = sd.getChildValue("url"); + String d = sd.getChildValue("derivation"); + String k = sd.getChildValue("kind"); + if (Utilities.isAbsoluteUrl(v)) { + warning(errors, IssueType.INVALID, e.line(), e.col(), path, ns(v).equals(ns(url)) || ns(v).equals(ns(url).replace("StructureDefinition/", "")), I18nConstants.SD_TYPE_NOT_MATCH_NS, v, url); + return rule(errors, IssueType.INVALID, e.line(), e.col(), path, "logical".equals(k), I18nConstants.SD_TYPE_NOT_LOGICAL, v, k); + } else { + boolean tok = false; + for (StructureDefinition t : context.fetchResourcesByType(StructureDefinition.class)) { + if (t.hasUserData("package") && t.getUserString("package").startsWith("hl7.fhir.r") && v.equals(t.getType())) { + tok = true; + } + } + if (tok) { + if (!(("http://hl7.org/fhir/StructureDefinition/"+v).equals(url))) { + return rule(errors, IssueType.INVALID, e.line(), e.col(), path, "constraint".equals(d), I18nConstants.SD_TYPE_NOT_DERIVED, v); + } else { + return true; + } + } else { + return rule(errors, IssueType.INVALID, e.line(), e.col(), path, tok, I18nConstants.SD_TYPE_NOT_LOCAL, v); + } + } + } + + private String ns(String url) { + return url.contains("/") ? url.substring(0, url.lastIndexOf("/")) : url; + } + private Object prepWSPresentation(String s) { if (Utilities.noString(s)) { return ""; 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 bec115546..2b9a8c2b6 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 @@ -69,14 +69,18 @@ public class StructureDefinitionValidator extends BaseValidator { public boolean validateStructureDefinition(List errors, Element src, NodeStack stack) { boolean ok = true; StructureDefinition sd = null; + String typeName = null; try { sd = loadAsSD(src); List snapshot = sd.getSnapshot().getElement(); sd.setSnapshot(null); + typeName = sd.getTypeName(); StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); if (warning(errors, IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), "StructureDefinition, so can't check the differential")) { if (rule(errors, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasDerivation(), I18nConstants.SD_MUST_HAVE_DERIVATION, sd.getUrl())) { + rule(errors, IssueType.NOTFOUND, stack.getLiteralPath(), base.getAbstract() || sd.hasKind() && sd.getKind() == base.getKind(), I18nConstants.SD_CONSTRAINED_KIND_NO_MATCH, sd.getKind().toCode(), base.getKind().toCode(), base.getType()); if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT) { + rule(errors, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasType() && sd.getType().equals(base.getType()), I18nConstants.SD_CONSTRAINED_TYPE_NO_MATCH, sd.getType(), base.getType()); List msgs = new ArrayList<>(); ProfileUtilities pu = new ProfileUtilities(context, msgs, null); pu.setXver(xverManager); @@ -100,6 +104,8 @@ public class StructureDefinitionValidator extends BaseValidator { int is = sd.getSnapshot().getElement().size(); ok = rule(errors, IssueType.NOTFOUND, stack.getLiteralPath(), was == is, I18nConstants.SNAPSHOT_EXISTING_PROBLEM, was, is) && ok; } + } else { + rule(errors, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasType() && !sd.getType().equals(base.getType()), I18nConstants.SD_SPECIALIZED_TYPE_MATCHES, sd.getType(), base.getType()); } } else { ok = false; @@ -116,28 +122,30 @@ public class StructureDefinitionValidator extends BaseValidator { List differentials = src.getChildrenByName("differential"); List snapshots = src.getChildrenByName("snapshot"); for (Element differential : differentials) { - ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd) && ok; + ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName) && ok; } for (Element snapshot : snapshots) { - ok = validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd) && ok; + ok = validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd, typeName) && ok; } return ok; } - private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) { + private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName) { 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) && ok; + ok = validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName) && ok; cc++; } return ok; } - private boolean validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) { + private boolean validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName) { boolean ok = true; boolean typeMustSupport = false; + String path = element.getNamedChildValue("path"); + rule(errors, IssueType.NOTFOUND, stack.getLiteralPath(), typeName == null || path == null || path.equals(typeName) || path.startsWith(typeName+"."), I18nConstants.SD_PATH_TYPE_MISMATCH, typeName, path); List types = element.getChildrenByName("type"); Set typeCodes = new HashSet<>(); Set characteristics = new HashSet<>(); @@ -173,14 +181,14 @@ 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, element.getChildValue("path")) && ok; + ok = validateElementType(errors, type, stack.push(type, -1, null, null), sd, path) && ok; } } if (typeMustSupport) { if (snapshot) { - ok = rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, element.getNamedChildValue("path")) && ok; + ok = rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, path) && ok; } else { - hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path")); + hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, path); } } if (element.hasChild("binding")) { @@ -188,7 +196,7 @@ public class StructureDefinitionValidator extends BaseValidator { ok = rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok; } Element binding = element.getNamedChild("binding"); - ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, element.getNamedChildValue("path")) && ok; + ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path) && ok; } else { // this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back // String bt = boundType(typeCodes); @@ -375,7 +383,9 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean validateBinding(List errors, Element binding, NodeStack stack, Set typeCodes, boolean snapshot, String path) { boolean ok = true; - ok = rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bindableType(typeCodes) != null, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString()) && ok; + if (bindableType(typeCodes) == null) { + ok = rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString()) && ok; + } if (!snapshot) { Set bindables = getListofBindableTypes(typeCodes); hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), bindables.size() <= 1, I18nConstants.SD_ED_BIND_MULTIPLE_TYPES, path, typeCodes.toString()); From c49a2c0fc564c4918ed1af53f894b1b09bc25e57 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 3 Nov 2022 15:59:42 +1100 Subject: [PATCH 2/2] Fix link to extension style --- .../src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index b7fd007c2..b0858ff25 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -238,7 +238,8 @@ public class ToolingExtensions { - public static final String WEB_EXTENSION_STYLE = "http://build.fhir.org/ig/FHIR/fhir-tools-ig/branches/master/format-extensions.html#extension-related-extensions"; + public static final String WEB_EXTENSION_STYLE = "http://build.fhir.org/ig/FHIR/fhir-tools-ig/format-extensions.html#extension-related-extensions"; + public static final String EXT_IGDEP_COMMENT = "http://hl7.org/fhir/tools/StructureDefinition/implementationguide-dependency-comment"; ; // specific extension helpers