Merge pull request #1271 from hapifhir/gg-202304-more-snapshot
Gg 202304 more snapshot
This commit is contained in:
commit
8f3367772c
|
@ -2,11 +2,16 @@
|
|||
|
||||
* 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
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
public class ElementDefinitionCounter {
|
||||
int count = 0;
|
||||
ElementDefinition focus;
|
||||
Set<String> 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<String, ElementDefinitionCounter> 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<String> 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);
|
||||
|
|
|
@ -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<String> notCanonical = new HashSet<String>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -941,4 +941,6 @@ public interface IWorkerContext {
|
|||
|
||||
public PEBuilder getProfiledElementBuilder(PEElementPropertiesPolicy elementProps, boolean fixedProps);
|
||||
|
||||
public boolean isForPublication();
|
||||
public void setForPublication(boolean value);
|
||||
}
|
|
@ -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().toCode())) {
|
||||
if (theRelation.equals(next.getRelation().toCode())) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = p.substring(3);
|
||||
}
|
||||
if (p.endsWith("</p>")) {
|
||||
p = p.substring(0, p.length()-4);
|
||||
}
|
||||
p = p.replace("</p>", " ");
|
||||
p = p.replace("<p>", "");
|
||||
while (p.contains("<p ")) {
|
||||
int start = p.indexOf("<p ");
|
||||
int end = start;
|
||||
while (end < p.length() && p.charAt(end) != '>') {
|
||||
end++;
|
||||
}
|
||||
p = p.substring(start, end);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public static boolean !isWhitespace(String s) {
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<Element> differentials = src.getChildrenByName("differential");
|
||||
List<Element> 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<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical) {
|
||||
private boolean validateElementList(List<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint) {
|
||||
boolean ok = true;
|
||||
List<Element> 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<ValidationMessage> errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical) {
|
||||
private boolean validateElementDefinition(List<ValidationMessage> 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(), snapshot || !constraint || !element.hasChild("meaningWhenMissing") || meaningWhenMissingAllowed(element), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path);
|
||||
|
||||
List<Element> types = element.getChildrenByName("type");
|
||||
Set<String> typeCodes = new HashSet<>();
|
||||
Set<String> characteristics = new HashSet<>();
|
||||
|
@ -312,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<String> set, String tc) {
|
||||
switch (tc) {
|
||||
case "boolean" : return addCharacteristicsForType(set);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue