From 035841f13eaf48528079f45fc8d4309ebe70d026 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Mon, 22 May 2023 21:07:17 +1000
Subject: [PATCH 01/10] #692 - error when meaning-when-missing found in
profiles
---
.../org/hl7/fhir/utilities/i18n/I18nConstants.java | 1 +
.../src/main/resources/Messages.properties | 2 +-
.../type/StructureDefinitionValidator.java | 14 +++++++++-----
3 files changed, 11 insertions(+), 6 deletions(-)
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 5b5dcf412..c2439259f 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
@@ -869,6 +869,7 @@ public class I18nConstants {
public static final String ED_PATH_WRONG_TYPE_MATCH = "ED_PATH_WRONG_TYPE_MATCH";
public static final String ATTEMPT_TO_CHANGE_SLICING = "ATTEMPT_TO_CHANGE_SLICING";
public static final String REPEAT_SLICING_IGNORED = "REPEAT_SLICING_IGNORED";
+ public static final String SD_ELEMENT_NOT_IN_CONSTRAINT = "SD_ELEMENT_NOT_IN_CONSTRAINT";
}
diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties
index c7d8d4fa5..9bd8f16e8 100644
--- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties
+++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties
@@ -923,4 +923,4 @@ SD_CONTEXT_SHOULD_NOT_BE_ELEMENT = Review the extension type: extensions should
ED_PATH_WRONG_TYPE_MATCH = The path must be ''{0}'' not ''{1}'' when the type list is not constrained
ATTEMPT_TO_CHANGE_SLICING = The element at {0} defines the slicing {1} but then an element in the slicing {2} tries to redefine the slicing to {3}
REPEAT_SLICING_IGNORED = The element at {0} defines the slicing but then an element in the slicing {2} repeats it, which is ignored
-
+SD_ELEMENT_NOT_IN_CONSTRAINT = The element definition for {1} has a property {0} which is not allowed in a profile
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 9cad656d9..9ed1ddc95 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
@@ -127,14 +127,16 @@ public class StructureDefinitionValidator extends BaseValidator {
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
ok = false;
}
+
List differentials = src.getChildrenByName("differential");
List snapshots = src.getChildrenByName("snapshot");
boolean logical = "logical".equals(src.getNamedChildValue("kind"));
+ boolean constraint = "constraint".equals(src.getNamedChildValue("derivation"));
for (Element differential : differentials) {
- ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical) && ok;
+ ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint) && ok;
}
for (Element snapshot : snapshots) {
- ok = validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd, typeName, logical) && ok;
+ ok = validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true, sd, typeName, logical, constraint) && ok;
}
return ok;
}
@@ -174,18 +176,18 @@ public class StructureDefinitionValidator extends BaseValidator {
}
}
- private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical) {
+ private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint) {
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, logical) && ok;
+ ok = validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName, logical, constraint) && ok;
cc++;
}
return ok;
}
- private boolean validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical) {
+ private boolean validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint) {
boolean ok = true;
boolean typeMustSupport = false;
String path = element.getNamedChildValue("path");
@@ -194,6 +196,8 @@ public class StructureDefinitionValidator extends BaseValidator {
rule(errors, "2023-01-17", IssueType.INVALID, stack.getLiteralPath(), path.contains(".") || !element.hasChild("slicing"), I18nConstants.SD_NO_SLICING_ON_ROOT, path);
}
+ rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), !constraint || !element.hasChild("meaningWhenMissing"), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path);
+
List types = element.getChildrenByName("type");
Set typeCodes = new HashSet<>();
Set characteristics = new HashSet<>();
From 49571de18ae3e9ab3d84fc0838612658112155d7 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 06:13:05 +1000
Subject: [PATCH 02/10] #1266 fix Bundle.getLink() for enumeration
---
org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Bundle.java | 2 +-
.../src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Bundle.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Bundle.java
index f0deecff1..f0af48d82 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Bundle.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Bundle.java
@@ -5307,7 +5307,7 @@ public class Bundle extends Resource implements IBaseBundle {
public BundleLinkComponent getLink(String theRelation) {
org.apache.commons.lang3.Validate.notBlank(theRelation, "theRelation may not be null or empty");
for (BundleLinkComponent next : getLink()) {
- if (theRelation.equals(next.getRelation())) {
+ if (theRelation.equals(next.getRelation().toCode())) {
return next;
}
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java
index 78b381156..030ee34a9 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java
@@ -127,7 +127,7 @@ public class ResourceUtilities {
public static String getLink(Bundle feed, String rel) {
for (BundleLinkComponent link : feed.getLink()) {
- if (link.getRelation().equals(rel))
+ if (link.getRelation().toCode().equals(rel))
return link.getUrl();
}
return null;
From 8a5c9c7ca65ff74bea4ad6a28bdd92ed0b289a59 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 17:37:11 +1000
Subject: [PATCH 03/10] Adjust handling of slicing min issues
---
.../profile/ProfilePathProcessor.java | 8 +---
.../conformance/profile/ProfileUtilities.java | 45 ++++++++++++-------
2 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java
index dfe5d9f8f..ea546a25b 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java
@@ -174,17 +174,13 @@ public class ProfilePathProcessor {
// in the simple case, source is not sliced.
if (!currentBase.hasSlicing() || currentBasePath.equals(getSlicing().getPath()))
{
- ElementDefinition currentRes = processSimplePath(currentBase, currentBasePath, diffMatches, typeList,
- cursors
- );
+ ElementDefinition currentRes = processSimplePath(currentBase, currentBasePath, diffMatches, typeList, cursors);
if (res == null) {
res = currentRes;
}
}
else {
- processPathWithSlicedBase(currentBase, currentBasePath, diffMatches, typeList,
- cursors
- );
+ processPathWithSlicedBase(currentBase, currentBasePath, diffMatches, typeList, cursors);
}
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java
index 2279c688b..51585d403 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java
@@ -135,6 +135,7 @@ public class ProfileUtilities extends TranslatingUtilities {
public class ElementDefinitionCounter {
int count = 0;
ElementDefinition focus;
+ Set names = new HashSet<>();
public ElementDefinitionCounter(ElementDefinition ed) {
focus = ed;
@@ -142,15 +143,16 @@ public class ProfileUtilities extends TranslatingUtilities {
public int update() {
if (count > focus.getMin()) {
- int was = focus.getMin();
- focus.setMin(count);
- return was;
+ return count;
}
return -1;
}
- public void count(ElementDefinition ed) {
- count = count + ed.getMin();
+ public boolean count(ElementDefinition ed, String name) {
+ count = count + ed.getMin();
+ boolean ok = !names.contains(name);
+ names.add(name);
+ return ok;
}
public ElementDefinition getFocus() {
@@ -725,13 +727,13 @@ public class ProfileUtilities extends TranslatingUtilities {
if (tn.contains("/")) {
tn = tn.substring(tn.lastIndexOf("/")+1);
}
- System.out.println("Check slicing for "+derived.getVersionedUrl());
+// System.out.println("Check slicing for "+derived.getVersionedUrl());
Map slices = new HashMap<>();
int i = 0;
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
if (ed.hasSlicing()) {
slices.put(ed.getPath(), new ElementDefinitionCounter(ed));
- System.out.println("Entering slicing for "+ed.getPath()+" ["+i+"]");
+// System.out.println("Entering slicing for "+ed.getPath()+" ["+i+"]");
} else {
Set toRemove = new HashSet<>();
for (String s : slices.keySet()) {
@@ -740,13 +742,14 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
for (String s : toRemove) {
- int was = slices.get(s).update();
- if (was > -1) {
- String msg = "The slice definition for "+slices.get(s).getFocus().getId()+" had a minimum of "+was+" but the slices added up to a minimum of "+slices.get(s).getFocus().getMin()+" so the value has been adjusted in the snapshot";
- System.out.println(msg);
+ int count = slices.get(s).update();
+ if (count > -1) {
+ String msg = "The slice definition for "+slices.get(s).getFocus().getId()+" has a minimum of "+slices.get(s).getFocus().getMin()+" but the slices add up to a minimum of "+count;
+ //+" so the value has been adjusted in the snapshot"; we don't adjust it because of downstream effects. But if it's for publication, they better get it right.
+// System.out.println(msg);
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION));
}
- System.out.println("Exiting slicing for "+s+" at "+ed.getPath()+" ["+i+"]");
+// System.out.println("Exiting slicing for "+s+" at "+ed.getPath()+" ["+i+"]");
slices.remove(s);
}
}
@@ -758,7 +761,10 @@ public class ProfileUtilities extends TranslatingUtilities {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, ValidationMessage.IssueSeverity.ERROR));
}
if (ed.hasSliceName() && slices.containsKey(ed.getPath())) {
- slices.get(ed.getPath()).count(ed);
+ if (!slices.get(ed.getPath()).count(ed, ed.getSliceName())) {
+ String msg = "Duplicate slice name "+ed.getSliceName()+" on "+ed.getId()+" (["+i+"])";
+ messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, ValidationMessage.IssueSeverity.ERROR));
+ }
}
i++;
}
@@ -2043,10 +2049,15 @@ public class ProfileUtilities extends TranslatingUtilities {
}
// Before applying changes, apply them to what's in the profile
StructureDefinition profile = null;
- if (base.hasSliceName())
+ if (base.hasSliceName()) {
profile = base.getType().size() == 1 && base.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, base.getTypeFirstRep().getProfile().get(0).getValue(), srcSD) : null;
- if (profile==null)
+ }
+ if (profile==null) {
profile = source.getType().size() == 1 && source.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, source.getTypeFirstRep().getProfile().get(0).getValue(), derivedSrc) : null;
+ if (profile != null && !"Extension".equals(profile.getType())) {
+ profile = null;
+ }
+ }
if (profile != null) {
ElementDefinition e = profile.getSnapshot().getElement().get(0);
String webroot = profile.getUserString("webroot");
@@ -2157,7 +2168,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (derived.hasMinElement()) {
if (!Base.compareDeep(derived.getMinElement(), base.getMinElement(), false)) {
if (derived.getMin() < base.getMin() && !derived.hasSliceName()) // in a slice, minimum cardinality rules do not apply
- messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than base min ("+Integer.toString(base.getMin())+")", ValidationMessage.IssueSeverity.ERROR));
+ messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than the base min ("+Integer.toString(base.getMin())+") in "+srcSD.getVersionedUrl(), ValidationMessage.IssueSeverity.ERROR));
base.setMinElement(derived.getMinElement().copy());
} else if (trimDifferential)
derived.setMinElement(null);
@@ -2168,7 +2179,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (derived.hasMaxElement()) {
if (!Base.compareDeep(derived.getMaxElement(), base.getMaxElement(), false)) {
if (isLargerMax(derived.getMax(), base.getMax()))
- messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived max ("+derived.getMax()+") cannot be greater than base max ("+base.getMax()+")", ValidationMessage.IssueSeverity.ERROR));
+ messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived max ("+derived.getMax()+") cannot be greater than the base max ("+base.getMax()+")", ValidationMessage.IssueSeverity.ERROR));
base.setMaxElement(derived.getMaxElement().copy());
} else if (trimDifferential)
derived.setMaxElement(null);
From a2e2ef714ed7024dcd788a855d20d949aeeab07c Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 17:39:08 +1000
Subject: [PATCH 04/10] Handle sub-slicing case where slice matches both the
slice definition and the sub-slice definition
---
.../fhir/r5/context/BaseWorkerContext.java | 17 +++++++++--
.../hl7/fhir/r5/context/ContextUtilities.java | 4 ++-
.../hl7/fhir/r5/context/IWorkerContext.java | 2 ++
.../java/org/hl7/fhir/r5/model/Coding.java | 2 +-
.../instance/InstanceValidator.java | 28 +++++++++++++++----
5 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
index fdc11fd65..9babd89fd 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
@@ -73,6 +73,7 @@ import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
+import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.Library;
import org.hl7.fhir.r5.model.Measure;
@@ -868,7 +869,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
// if that failed, we try to expand on the server
if (addDependentResources(p, vs)) {
- p.addParameter().setName("cache-id").setValue(new StringType(tcc.getCacheId()));
+ p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
if (noTerminologyServer) {
@@ -1147,7 +1148,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
boolean cached = addDependentResources(p, vs);
if (cached) {
- p.addParameter().setName("cache-id").setValue(new StringType(tcc.getCacheId()));
+ p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
return p;
}
@@ -1276,7 +1277,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
addDependentResources(pin, vs);
}
if (cache) {
- pin.addParameter().setName("cache-id").setValue(new StringType(tcc.getCacheId()));
+ pin.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
for (ParametersParameterComponent pp : pin.getParameter()) {
if (pp.getName().equals("profile")) {
@@ -1917,6 +1918,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private Set notCanonical = new HashSet();
protected IWorkerContextManager.IPackageLoadingTracker packageTracker;
+ private boolean forPublication;
@Override
public Resource fetchResourceById(String type, String uri) {
@@ -2467,4 +2469,13 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
// TODO Auto-generated method stub
return new PEBuilder(this, elementProps, fixedProps);
}
+
+ public boolean isForPublication() {
+ return forPublication;
+ }
+
+ public void setForPublication(boolean value) {
+ forPublication = value;
+ }
+
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java
index 62950a9c8..6a402c70d 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java
@@ -274,6 +274,7 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
ProfileUtilities pu = new ProfileUtilities(context, msgs, this);
pu.setAutoFixSliceNames(true);
pu.setThrowException(false);
+ pu.setForPublication(context.isForPublication());
if (xverManager == null) {
xverManager = new XVerExtensionManager(context);
}
@@ -282,8 +283,9 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
pu.sortDifferential(sd, p, p.getUrl(), errors, true);
}
pu.setDebug(false);
- for (String err : errors)
+ for (String err : errors) {
msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getWebPath(), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR));
+ }
pu.generateSnapshot(sd, p, p.getUrl(), sd.getUserString("webroot"), p.getName());
for (ValidationMessage msg : msgs) {
if ((!ignoreProfileErrors && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL)
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java
index 9b90702ea..b54fd07a9 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java
@@ -941,4 +941,6 @@ public interface IWorkerContext {
public PEBuilder getProfiledElementBuilder(PEElementPropertiesPolicy elementProps, boolean fixedProps);
+ public boolean isForPublication();
+ public void setForPublication(boolean value);
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java
index 890cb700d..198cdae79 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java
@@ -544,7 +544,7 @@ public class Coding extends DataType implements IBaseCoding, ICompositeType, ICo
base = base+"|"+getVersion();
base = base + "#"+getCode();
if (hasDisplay())
- base = base+": "+getDisplay();
+ base = base+": '"+getDisplay()+"'";
return base;
}
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 093c6a696..92176065a 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
@@ -5968,14 +5968,30 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
if (match) {
+ boolean update = true;
boolean isOk = ei.definition == null || ei.definition == slicer || (ei.definition.getPath().endsWith("[x]") && ed.getPath().startsWith(ei.definition.getPath().replace("[x]", "")));
+ if (!isOk) {
+ // is this a subslice? then we put it in as a replacement
+ String existingName = ei.definition == null || !ei.definition.hasSliceName() ? null : ei.definition.getSliceName();
+ String matchingName = ed.hasSliceName() ? ed.getSliceName() : null;
+ if (existingName != null && matchingName != null) {
+ if (matchingName.startsWith(existingName+"/")) {
+ isOk = true;
+ } else if (existingName.startsWith(matchingName+"/")) {
+ update = false;
+ isOk = true;
+ }
+ }
+ }
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), isOk, I18nConstants.VALIDATION_VAL_PROFILE_MATCHMULTIPLE, profile.getVersionedUrl(), (ei.definition == null || !ei.definition.hasSliceName() ? "" : ei.definition.getSliceName()), (ed.hasSliceName() ? ed.getSliceName() : ""))) {
- ei.definition = ed;
- if (ei.slice == null) {
- ei.index = i;
- } else {
- ei.index = sliceOffset;
- ei.sliceindex = i - (sliceOffset + 1);
+ if (update) {
+ ei.definition = ed;
+ if (ei.slice == null) {
+ ei.index = i;
+ } else {
+ ei.index = sliceOffset;
+ ei.sliceindex = i - (sliceOffset + 1);
+ }
}
}
} else if (childUnsupportedSlicing) {
From 10a0cc7220a61a5f4e35ffa0c55f801556bc78e3 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 17:40:13 +1000
Subject: [PATCH 05/10] Allow meaningWhenMissing on extension definitions
---
.../instance/type/StructureDefinitionValidator.java | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
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 9ed1ddc95..6afb3ea5f 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
@@ -196,7 +196,7 @@ public class StructureDefinitionValidator extends BaseValidator {
rule(errors, "2023-01-17", IssueType.INVALID, stack.getLiteralPath(), path.contains(".") || !element.hasChild("slicing"), I18nConstants.SD_NO_SLICING_ON_ROOT, path);
}
- rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), !constraint || !element.hasChild("meaningWhenMissing"), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path);
+ rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), snapshot || !constraint || !element.hasChild("meaningWhenMissing") || meaningWhenMissingAllowed(element), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path);
List types = element.getChildrenByName("type");
Set typeCodes = new HashSet<>();
@@ -316,6 +316,12 @@ public class StructureDefinitionValidator extends BaseValidator {
return ok;
}
+ private boolean meaningWhenMissingAllowed(Element element) {
+ // allowed to use meaningWhenMissing on the root of an element to say what it means when the extension
+ // is not present.
+ return "Extension".equals(element.getPath()) || (element.getPath().endsWith(".extension"));
+ }
+
private boolean addCharacteristics(Set set, String tc) {
switch (tc) {
case "boolean" : return addCharacteristicsForType(set);
From c48fd2b818e509a4fe2161ea4ece2a71e296af55 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 17:41:03 +1000
Subject: [PATCH 06/10] All to strip all paragraphs from generated html
(post-markdown)
---
.../tests/SnapShotGenerationXTests.java | 10 ++---
.../org.hl7.fhir.validation/4.0.1/loinc.cache | 19 ++++++++++
.../4.0.1/snomed.cache | 38 +++++++++++++++++++
.../org.hl7.fhir.validation/4.0.1/ucum.cache | 16 ++++++++
4 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java
index 203d599c0..901d64d35 100644
--- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java
+++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java
@@ -180,7 +180,7 @@ public class SnapShotGenerationXTests {
else
source = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-input.xml"));
if (!fail)
- expected = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-expected.xml"));
+ expected = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-output.xml"));
if (!Utilities.noString(include))
included = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", include + ".xml"));
if (!Utilities.noString(register)) {
@@ -471,8 +471,7 @@ public class SnapShotGenerationXTests {
pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors, false);
if (!errors.isEmpty())
throw new FHIRException(errors.get(0));
- IOUtils.copy(TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", test.getId() + "-expected.xml"), new FileOutputStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-expected.xml")));
- new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-actual.xml")), test.getOutput());
+ new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-output.xml")), test.getOutput());
Assertions.assertTrue(test.expected.equalsDeep(test.output), "Output does not match expected");
}
@@ -542,11 +541,10 @@ public class SnapShotGenerationXTests {
if (!fail) {
test.output = output;
UtilitiesXTests.context(version).cacheResource(output);
- File dst = new File(UtilitiesXTests.tempFile("snapshot", test.getId() + "-expected.xml"));
+ File dst = new File(UtilitiesXTests.tempFile("snapshot", test.getId() + "-output.xml"));
if (dst.exists())
dst.delete();
- IOUtils.copy(TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", test.getId() + "-expected.xml"), new FileOutputStream(dst));
- new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-actual.xml")), output);
+ new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-output.xml")), output);
StructureDefinition t1 = test.expected.copy();
t1.setText(null);
StructureDefinition t2 = test.output.copy();
diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache
index db0a89521..fdb128699 100644
--- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache
+++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache
@@ -3443,3 +3443,22 @@ v: {
"class" : "SERVER_ERROR"
}
-------------------------------------------------------------------------------------
+{"code" : {
+ "system" : "http://loinc.org",
+ "version" : "2.71",
+ "code" : "29463-7",
+ "display" : "Body weight"
+}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
+ "resourceType" : "Parameters",
+ "parameter" : [{
+ "name" : "profile-url",
+ "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
+ }]
+}}####
+v: {
+ "display" : "Body weight",
+ "code" : "29463-7",
+ "system" : "http://loinc.org",
+ "version" : "2.74"
+}
+-------------------------------------------------------------------------------------
diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache
index b51a4f158..07ca7028f 100644
--- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache
+++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache
@@ -2150,3 +2150,41 @@ v: {
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------
+{"code" : {
+ "system" : "http://snomed.info/sct",
+ "version" : "http://snomed.info/sct/900000000000207008/version/20210731",
+ "code" : "27113001",
+ "display" : "Body weight (observable entity)"
+}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
+ "resourceType" : "Parameters",
+ "parameter" : [{
+ "name" : "profile-url",
+ "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
+ }]
+}}####
+v: {
+ "display" : "Body weight",
+ "code" : "27113001",
+ "system" : "http://snomed.info/sct",
+ "version" : "http://snomed.info/sct/900000000000207008/version/20210731"
+}
+-------------------------------------------------------------------------------------
+{"code" : {
+ "system" : "http://snomed.info/sct",
+ "version" : "http://snomed.info/sct/900000000000207008/version/20210731",
+ "code" : "38266002",
+ "display" : "Entire body as a whole (body structure)"
+}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
+ "resourceType" : "Parameters",
+ "parameter" : [{
+ "name" : "profile-url",
+ "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
+ }]
+}}####
+v: {
+ "display" : "Entire body as a whole",
+ "code" : "38266002",
+ "system" : "http://snomed.info/sct",
+ "version" : "http://snomed.info/sct/900000000000207008/version/20210731"
+}
+-------------------------------------------------------------------------------------
diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/ucum.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/ucum.cache
index f44ea8047..16d6dc302 100644
--- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/ucum.cache
+++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/ucum.cache
@@ -420,3 +420,19 @@ v: {
"version" : "2.0.1"
}
-------------------------------------------------------------------------------------
+{"code" : {
+ "system" : "http://unitsofmeasure.org",
+ "code" : "KG"
+}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
+ "resourceType" : "Parameters",
+ "parameter" : [{
+ "name" : "profile-url",
+ "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
+ }]
+}}####
+v: {
+ "severity" : "error",
+ "error" : "Error processing Unit: 'KG': The unit \"KG\" is unknown at character 1; Unknown Code 'KG' in the system 'http://unitsofmeasure.org'; The provided code http://unitsofmeasure.org#KG is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)",
+ "class" : "UNKNOWN"
+}
+-------------------------------------------------------------------------------------
From 0bcb2ab268a38a3d17301be398c19103d182bb05 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 17:41:16 +1000
Subject: [PATCH 07/10] Strip all paras
---
.../org/hl7/fhir/utilities/Utilities.java | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java
index 47f3f7b6d..2a578b6ae 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java
@@ -1951,6 +1951,30 @@ public class Utilities {
return p;
}
+ public static String stripAllPara(String p) {
+ if (noString(p)) {
+ return "";
+ }
+ p = p.trim();
+ if (p.startsWith("")) {
+ p = p.substring(3);
+ }
+ if (p.endsWith("
")) {
+ p = p.substring(0, p.length()-4);
+ }
+ p = p.replace("
", " ");
+ p = p.replace("", "");
+ while (p.contains("
') {
+ end++;
+ }
+ p = p.substring(start, end);
+ }
+ return p;
+ }
+
//public static boolean !isWhitespace(String s) {
From f274889c7e3c7c6e5ad6dfdc5fe7d783da867389 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 17:41:31 +1000
Subject: [PATCH 08/10] release notes
---
RELEASE_NOTES.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 13ab15751..df02c718a 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -2,11 +2,15 @@
* Snapshot Generation Changes:
** Check for slicenames without any slicing
+** Check that slice names are unique
** Check for additional slicing rules in a set of slices
** Check that the minimum cardinality of a set of slices is correct
* Clean up duplicate errors when dates/dateTimes/instants have invalid formats
* Handle unknown code systems consistently when validating coded elements
+* Handle sub-slicing case where slice matches both the slice definition and the sub-slice definition
## Other code changes
* Add support for R4B to loader
+* Change type if cache-id parameter
+
From 6ded6410b643f6a3b548466a001b18e5c8048974 Mon Sep 17 00:00:00 2001
From: Grahame Grieve
Date: Tue, 23 May 2023 20:47:49 +1000
Subject: [PATCH 09/10] just produce the output every time
---
.../java/org/hl7/fhir/validation/tests/ValidationTests.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java
index 0bca11e59..0736a648a 100644
--- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java
+++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java
@@ -107,7 +107,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
}
public final static boolean PRINT_OUTPUT_TO_CONSOLE = true;
- private static final boolean BUILD_NEW = false;
+ private static final boolean BUILD_NEW = true;
private static final boolean CLONE = true;
@Parameters(name = "{index}: id {0}")
From 5458c2c78b17d82ab097c22dffd63f508dfa280d Mon Sep 17 00:00:00 2001
From: dotasek
Date: Tue, 23 May 2023 16:16:18 -0400
Subject: [PATCH 10/10] Bump PR with blank line
---
RELEASE_NOTES.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index df02c718a..0e104971d 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -14,3 +14,4 @@
* Add support for R4B to loader
* Change type if cache-id parameter
+