Merge pull request #1268 from hapifhir/gg-202304-snapshot-fixes

Gg 202304 snapshot fixes
This commit is contained in:
Grahame Grieve 2023-05-22 19:09:45 +10:00 committed by GitHub
commit bd49a13d6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 885 additions and 123 deletions

View File

@ -1,7 +1,12 @@
## Validator Changes ## Validator Changes
* no changes * Snapshot Generation Changes:
** Check for slicenames without any slicing
** 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
## Other code changes ## Other code changes
* no changes * Add support for R4B to loader

View File

@ -75,6 +75,8 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader {
protected BaseLoaderR5 loaderFactory(NpmPackage npm) throws JsonSyntaxException, IOException { protected BaseLoaderR5 loaderFactory(NpmPackage npm) throws JsonSyntaxException, IOException {
if (VersionUtilities.isR5Plus(npm.fhirVersion())) { if (VersionUtilities.isR5Plus(npm.fhirVersion())) {
return new R5ToR5Loader(types, lkp.forNewPackage(npm)); return new R5ToR5Loader(types, lkp.forNewPackage(npm));
} else if (VersionUtilities.isR4BVer(npm.fhirVersion())) {
return new R4BToR5Loader(types, lkp.forNewPackage(npm), npm.version());
} else if (VersionUtilities.isR4Ver(npm.fhirVersion())) { } else if (VersionUtilities.isR4Ver(npm.fhirVersion())) {
return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.version()); return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.version());
} else if (VersionUtilities.isR3Ver(npm.fhirVersion())) { } else if (VersionUtilities.isR3Ver(npm.fhirVersion())) {

View File

@ -8,14 +8,20 @@ import java.util.Set;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.ElementRedirection; import org.hl7.fhir.r5.conformance.ElementRedirection;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingComponent;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -267,12 +273,28 @@ public class ProfilePathProcessor {
if (!diffMatches.get(0).hasSlicing()) if (!diffMatches.get(0).hasSlicing())
outcome.setSlicing(profileUtilities.makeExtensionSlicing()); outcome.setSlicing(profileUtilities.makeExtensionSlicing());
else else {
outcome.setSlicing(diffMatches.get(0).getSlicing().copy()); outcome.setSlicing(diffMatches.get(0).getSlicing().copy());
for (int i = 1; i < diffMatches.size(); i++) {
if (diffMatches.get(i).hasSlicing()) {
if (!slicingMatches(diffMatches.get(0).getSlicing(), diffMatches.get(i).getSlicing())) {
profileUtilities.getMessages().add(new ValidationMessage(Source.InstanceValidator, ValidationMessage.IssueType.BUSINESSRULE, diffMatches.get(0).getPath(),
profileUtilities.getContext().formatMessage(I18nConstants.ATTEMPT_TO_CHANGE_SLICING, diffMatches.get(0).getId(), slicingSummary(diffMatches.get(0).getSlicing()), diffMatches.get(i).getId(), slicingSummary(diffMatches.get(i).getSlicing())),
ValidationMessage.IssueSeverity.ERROR));
} else {
profileUtilities.getMessages().add(new ValidationMessage(Source.InstanceValidator, ValidationMessage.IssueType.BUSINESSRULE, diffMatches.get(0).getPath(),
profileUtilities.getContext().formatMessage(I18nConstants.ATTEMPT_TO_CHANGE_SLICING, diffMatches.get(0).getId(), diffMatches.get(i).getId()),
IssueSeverity.INFORMATION));
}
}
}
}
if (cursors.resultPathBase != null) { if (cursors.resultPathBase != null) {
if (!outcome.getPath().startsWith(cursors.resultPathBase)) if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
} }
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
slicerElement = outcome; slicerElement = outcome;
@ -337,6 +359,20 @@ public class ProfilePathProcessor {
cursors.diffCursor = newDiffLimit + 1; cursors.diffCursor = newDiffLimit + 1;
} }
private String slicingSummary(ElementDefinitionSlicingComponent s) {
return s.toString();
}
private boolean slicingMatches(ElementDefinitionSlicingComponent s1, ElementDefinitionSlicingComponent s2) {
if ((!s1.hasOrdered() && s2.hasOrdered()) || (s1.hasOrdered() && s2.hasOrdered() && !Base.compareDeep(s1.getOrderedElement(), s2.getOrderedElement(), false))) {
return false;
}
if ((!s1.hasRules() && s2.hasRules()) || (s1.hasRules() && s2.hasRules() && !Base.compareDeep(s1.getRulesElement(), s2.getRulesElement(), false))) {
return false;
}
return Base.compareDeep(s1.getDiscriminator(), s2.getDiscriminator(), false);
}
private void processSimplePathWhereDiffsConstrainTypes(String currentBasePath, List<ElementDefinition> diffMatches, List<TypeSlice> typeList, ProfilePathProcessorState cursors) { private void processSimplePathWhereDiffsConstrainTypes(String currentBasePath, List<ElementDefinition> diffMatches, List<TypeSlice> typeList, ProfilePathProcessorState cursors) {
int start = 0; int start = 0;
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
@ -344,13 +380,14 @@ public class ProfilePathProcessor {
ElementDefinition elementToRemove = null; ElementDefinition elementToRemove = null;
boolean shortCut = !typeList.isEmpty() && typeList.get(0).getType() != null; boolean shortCut = !typeList.isEmpty() && typeList.get(0).getType() != null;
// we come here whether they are sliced in the diff, or whether the short cut is used. // we come here whether they are sliced in the diff, or whether the short cut is used.
String path = diffMatches.get(0).getPath();
if (shortCut) { if (shortCut) {
// this is the short cut method, we've just dived in and specified a type slice. // this is the short cut method, we've just dived in and specified a type slice.
// in R3 (and unpatched R4, as a workaround right now... // in R3 (and unpatched R4, as a workaround right now...
if (!VersionUtilities.isR4Plus(profileUtilities.getContext().getVersion()) || !profileUtilities.isNewSlicingProcessing()) { // newSlicingProcessing is a work around for editorial loop dependency if (!VersionUtilities.isR4Plus(profileUtilities.getContext().getVersion()) || !profileUtilities.isNewSlicingProcessing()) { // newSlicingProcessing is a work around for editorial loop dependency
// we insert a cloned element with the right types at the start of the diffMatches // we insert a cloned element with the right types at the start of the diffMatches
ElementDefinition ed = new ElementDefinition(); ElementDefinition ed = new ElementDefinition();
ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); ed.setPath(profileUtilities.determineTypeSlicePath(path, currentBasePath));
for (TypeSlice ts : typeList) for (TypeSlice ts : typeList)
ed.addType().setCode(ts.getType()); ed.addType().setCode(ts.getType());
ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent());
@ -365,7 +402,7 @@ public class ProfilePathProcessor {
// so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type.
// see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element
ElementDefinition ed = new ElementDefinition(); ElementDefinition ed = new ElementDefinition();
ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); ed.setPath(profileUtilities.determineTypeSlicePath(path, currentBasePath));
ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent());
ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this");
ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED);
@ -374,6 +411,13 @@ public class ProfilePathProcessor {
getDifferential().getElement().add(newDiffCursor, ed); getDifferential().getElement().add(newDiffCursor, ed);
elementToRemove = ed; elementToRemove = ed;
} }
} else { // if it's not a short cut, then the path has to be correct
String t1 = currentBasePath.substring(currentBasePath.lastIndexOf(".")+1);
String t2 = path.substring(path.lastIndexOf(".")+1);
if (!t1.equals(t2)) {
throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ED_PATH_WRONG_TYPE_MATCH, path.replace(t2, t1), path));
}
} }
int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor);
// the first element is setting up the slicing // the first element is setting up the slicing
@ -429,7 +473,7 @@ public class ProfilePathProcessor {
.processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, .processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor,
cursors.contextName, cursors.resultPathBase)); cursors.contextName, cursors.resultPathBase));
if (elementDefinition == null) if (elementDefinition == null)
throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, path));
// now set up slicing on the e (cause it was wiped by what we called. // now set up slicing on the e (cause it was wiped by what we called.
elementDefinition.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); elementDefinition.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent());
elementDefinition.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); elementDefinition.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this");
@ -607,6 +651,7 @@ public class ProfilePathProcessor {
cursors.resultPathBase = outcome.getPath(); cursors.resultPathBase = outcome.getPath();
else if (!outcome.getPath().startsWith(cursors.resultPathBase)) else if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
cursors.baseCursor++; cursors.baseCursor++;
cursors.diffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)) + 1; cursors.diffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)) + 1;
@ -731,6 +776,7 @@ public class ProfilePathProcessor {
cursors.resultPathBase = outcome.getPath(); cursors.resultPathBase = outcome.getPath();
else if (!outcome.getPath().startsWith(cursors.resultPathBase)) else if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), cursors.resultPathBase)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), cursors.resultPathBase));
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) { if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) {
// well, the profile walks into this, so we need to as well // well, the profile walks into this, so we need to as well
@ -756,6 +802,9 @@ public class ProfilePathProcessor {
} }
} }
} }
if (!profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) {
cursors.diffCursor++;
}
int start = cursors.diffCursor; int start = cursors.diffCursor;
while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + "."))
cursors.diffCursor++; cursors.diffCursor++;
@ -893,6 +942,7 @@ public class ProfilePathProcessor {
diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called
} }
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
if (!diffMatches.get(0).hasSliceName()) { // it's not real content, just the slice if (!diffMatches.get(0).hasSliceName()) { // it's not real content, just the slice
@ -942,6 +992,8 @@ public class ProfilePathProcessor {
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) { for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) {
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy()); outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy());
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
} }
} }
@ -978,6 +1030,7 @@ public class ProfilePathProcessor {
cursors.diffCursor = newDiffLimit + 1; cursors.diffCursor = newDiffLimit + 1;
diffpos++; diffpos++;
} else { } else {
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
cursors.baseCursor++; cursors.baseCursor++;
// just copy any children on the base // just copy any children on the base
@ -988,6 +1041,7 @@ public class ProfilePathProcessor {
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
outcome.setUserData(profileUtilities.UD_BASE_PATH, outcome.getPath()); outcome.setUserData(profileUtilities.UD_BASE_PATH, outcome.getPath());
outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl()); outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl());
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
cursors.baseCursor++; cursors.baseCursor++;
} }
@ -1016,6 +1070,7 @@ public class ProfilePathProcessor {
outcome.setMin(0); // we're in a slice, so it's only a mandatory if it's explicitly marked so outcome.setMin(0); // we're in a slice, so it's only a mandatory if it's explicitly marked so
if (!outcome.getPath().startsWith(cursors.resultPathBase)) if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived()); profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived());
profileUtilities.removeStatusExtensions(outcome); profileUtilities.removeStatusExtensions(outcome);
@ -1079,6 +1134,12 @@ public class ProfilePathProcessor {
cursors.baseCursor++; cursors.baseCursor++;
} }
private void debugCheck(ElementDefinition outcome) {
if (outcome.getPath().startsWith("List.") && "http://nictiz.nl/fhir/StructureDefinition/Bundle-MedicationOverview".equals(url)) {
System.out.println("wrong!");
}
}
private void processPathWithSlicedBaseWhereDiffsConstrainTypes(String currentBasePath, List<ElementDefinition> diffMatches, List<TypeSlice> typeList, ProfilePathProcessorState cursors) { private void processPathWithSlicedBaseWhereDiffsConstrainTypes(String currentBasePath, List<ElementDefinition> diffMatches, List<TypeSlice> typeList, ProfilePathProcessorState cursors) {
int start = 0; int start = 0;
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
@ -1252,6 +1313,7 @@ public class ProfilePathProcessor {
cursors.resultPathBase = outcome.getPath(); cursors.resultPathBase = outcome.getPath();
else if (!outcome.getPath().startsWith(cursors.resultPathBase)) else if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
debugCheck(outcome);
getResult().getElement().add(outcome); getResult().getElement().add(outcome);
// the profile walks into this, so we need to as well // the profile walks into this, so we need to as well
// did we implicitly step into a new type? // did we implicitly step into a new type?
@ -1295,6 +1357,7 @@ public class ProfilePathProcessor {
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
if (!outcome.getPath().startsWith(cursors.resultPathBase)) if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase)); throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase));
debugCheck(outcome);
getResult().getElement().add(outcome); // so we just copy it in getResult().getElement().add(outcome); // so we just copy it in
outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl()); outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl());
outcome.setUserData(profileUtilities.UD_BASE_PATH, cursors.resultPathBase); outcome.setUserData(profileUtilities.UD_BASE_PATH, cursors.resultPathBase);

View File

@ -49,6 +49,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.ElementRedirection; import org.hl7.fhir.r5.conformance.ElementRedirection;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.AllowUnknownProfile; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.AllowUnknownProfile;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ElementDefinitionCounter;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.ObjectConverter; import org.hl7.fhir.r5.elementmodel.ObjectConverter;
import org.hl7.fhir.r5.elementmodel.Property; import org.hl7.fhir.r5.elementmodel.Property;
@ -56,6 +57,7 @@ import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.BooleanType; import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Element;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType; import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBaseComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBaseComponent;
@ -130,6 +132,33 @@ import org.hl7.fhir.utilities.xml.SchematronWriter.Section;
*/ */
public class ProfileUtilities extends TranslatingUtilities { public class ProfileUtilities extends TranslatingUtilities {
public class ElementDefinitionCounter {
int count = 0;
ElementDefinition focus;
public ElementDefinitionCounter(ElementDefinition ed) {
focus = ed;
}
public int update() {
if (count > focus.getMin()) {
int was = focus.getMin();
focus.setMin(count);
return was;
}
return -1;
}
public void count(ElementDefinition ed) {
count = count + ed.getMin();
}
public ElementDefinition getFocus() {
return focus;
}
}
public enum MappingMergeModeOption { public enum MappingMergeModeOption {
DUPLICATE, // if there's more than one mapping for the same URI, just keep them all DUPLICATE, // if there's more than one mapping for the same URI, just keep them all
IGNORE, // if there's more than one, keep the first IGNORE, // if there's more than one, keep the first
@ -288,6 +317,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private Map<ElementDefinition, SourcedChildDefinitions> childMapCache = new HashMap<>(); private Map<ElementDefinition, SourcedChildDefinitions> childMapCache = new HashMap<>();
private AllowUnknownProfile allowUnknownProfile = AllowUnknownProfile.ALL_TYPES; private AllowUnknownProfile allowUnknownProfile = AllowUnknownProfile.ALL_TYPES;
private MappingMergeModeOption mappingMergeMode = MappingMergeModeOption.APPEND; private MappingMergeModeOption mappingMergeMode = MappingMergeModeOption.APPEND;
private boolean forPublication;
public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) { public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) {
super(); super();
@ -690,6 +720,49 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} }
} }
// check slicing is ok while we're at it. and while we're doing this. update the minimum count if we need to
String tn = derived.getType();
if (tn.contains("/")) {
tn = tn.substring(tn.lastIndexOf("/")+1);
}
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+"]");
} else {
Set<String> toRemove = new HashSet<>();
for (String s : slices.keySet()) {
if (Utilities.charCount(s, '.') >= Utilities.charCount(ed.getPath(), '.') && !s.equals(ed.getPath())) {
toRemove.add(s);
}
}
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);
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+"]");
slices.remove(s);
}
}
if (ed.getPath().contains(".") && !ed.getPath().startsWith(tn+".")) {
throw new Error("The element "+ed.getId()+" in the profile '"+derived.getVersionedUrl()+" (["+i+"]) doesn't have the right path (should start with "+tn+".");
}
if (ed.hasSliceName() && !slices.containsKey(ed.getPath())) {
String msg = "The element "+ed.getId()+" (["+i+"]) launches straight into slicing without the slicing being set up properly first";
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);
}
i++;
}
// last, check for wrong profiles or target profiles // last, check for wrong profiles or target profiles
for (ElementDefinition ed : derived.getSnapshot().getElement()) { for (ElementDefinition ed : derived.getSnapshot().getElement()) {
for (TypeRefComponent t : ed.getType()) { for (TypeRefComponent t : ed.getType()) {
@ -3978,5 +4051,16 @@ public class ProfileUtilities extends TranslatingUtilities {
return defn.getIsModifier(); return defn.getIsModifier();
} }
public boolean isForPublication() {
return forPublication;
}
public void setForPublication(boolean forPublication) {
this.forPublication = forPublication;
}
public List<ValidationMessage> getMessages() {
return messages;
}
} }

View File

@ -943,6 +943,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (!t.hasResult()) { if (!t.hasResult()) {
try { try {
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs); ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs);
vsc.setThrowToServer(options.isUseServer() && tcc.getClient() != null);
ValidationResult res = vsc.validateCode("Coding", t.getCoding()); ValidationResult res = vsc.validateCode("Coding", t.getCoding());
if (txCache != null) { if (txCache != null) {
txCache.cacheValidation(t.getCacheToken(), res, TerminologyCache.TRANSIENT); txCache.cacheValidation(t.getCacheToken(), res, TerminologyCache.TRANSIENT);
@ -1059,12 +1060,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
} }
List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
Set<String> unknownSystems = new HashSet<>();
String localError = null; String localError = null;
if (options.isUseClient()) { if (options.isUseClient()) {
// ok, first we try to validate locally // ok, first we try to validate locally
try { try {
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs, ctxt); ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs, ctxt);
vsc.setUnknownSystems(unknownSystems);
vsc.setThrowToServer(options.isUseServer() && tcc.getClient() != null);
if (!ValueSetUtilities.isServerSide(code.getSystem())) { if (!ValueSetUtilities.isServerSide(code.getSystem())) {
res = vsc.validateCode(path, code); res = vsc.validateCode(path, code);
if (txCache != null) { if (txCache != null) {
@ -1084,7 +1088,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
} }
if (localError != null && tcc.getClient() == null) { if (localError != null && tcc.getClient() == null) {
return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.UNKNOWN, issues); if (unknownSystems.size() > 0) {
return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED, issues).setUnknownSystems(unknownSystems);
} else {
return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.UNKNOWN, issues);
}
} }
if (!options.isUseServer()) { if (!options.isUseServer()) {
return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localError), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues); return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localError), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues);
@ -1204,11 +1212,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
codeSystemsUsed.add(c.getSystem()); codeSystemsUsed.add(c.getSystem());
} }
} }
Set<String> unknownSystems = new HashSet<>();
if (options.isUseClient()) { if (options.isUseClient()) {
// ok, first we try to validate locally // ok, first we try to validate locally
try { try {
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs); ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs);
vsc.setUnknownSystems(unknownSystems);
vsc.setThrowToServer(options.isUseServer() && tcc.getClient() != null);
res = vsc.validateCode("CodeableConcept", code); res = vsc.validateCode("CodeableConcept", code);
txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT); txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT);
return res; return res;
@ -1349,6 +1360,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
version = ((PrimitiveType<?>) p.getValue()).asStringValue(); version = ((PrimitiveType<?>) p.getValue()).asStringValue();
} else if (p.getName().equals("code")) { } else if (p.getName().equals("code")) {
code = ((PrimitiveType<?>) p.getValue()).asStringValue(); code = ((PrimitiveType<?>) p.getValue()).asStringValue();
} else if (p.getName().equals("x-caused-by-unknown-system")) {
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
} else if (p.getName().equals("cause")) { } else if (p.getName().equals("cause")) {
try { try {
IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue()); IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue());

View File

@ -123,6 +123,7 @@ public interface IWorkerContext {
private String diagnostics; private String diagnostics;
private List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
private CodeableConcept codeableConcept; private CodeableConcept codeableConcept;
private Set<String> unknownSystems;
@Override @Override
public String toString() { public String toString() {
@ -240,6 +241,11 @@ public interface IWorkerContext {
return this; return this;
} }
public ValidationResult addToMessage(String message) {
this.message = this.message == null ? message : this.message +"; "+ message;
return this;
}
public ValidationResult setErrorClass(TerminologyServiceErrorClass errorClass) { public ValidationResult setErrorClass(TerminologyServiceErrorClass errorClass) {
this.errorClass = errorClass; this.errorClass = errorClass;
return this; return this;
@ -289,6 +295,15 @@ public interface IWorkerContext {
return codeableConcept; return codeableConcept;
} }
public Set<String> getUnknownSystems() {
return unknownSystems;
}
public ValidationResult setUnknownSystems(Set<String> unknownSystems) {
this.unknownSystems = unknownSystems;
return this;
}
} }
public class CodingValidationRequest { public class CodingValidationRequest {

View File

@ -113,6 +113,9 @@ public class Manager {
} }
public static ParserBase makeParser(IWorkerContext context, FhirFormat format) { public static ParserBase makeParser(IWorkerContext context, FhirFormat format) {
if (format == null) {
throw new Error("Programming logic error: no format known");
}
switch (format) { switch (format) {
case JSON : return new JsonParser(context); case JSON : return new JsonParser(context);
case XML : return new XmlParser(context); case XML : return new XmlParser(context);

View File

@ -1413,12 +1413,17 @@ public class ElementDefinition extends BackboneType implements ICompositeType {
, ordered, rules); , ordered, rules);
} }
public String fhirType() { public String fhirType() {
return "ElementDefinition.slicing"; return "ElementDefinition.slicing";
} }
} @Override
public String toString() {
return (ordered == null ? "??" : "true".equals(ordered.asStringValue()) ? "ordered" : "unordered")+"/"+
(rules == null ? "??" : rules.asStringValue())+" "+discriminator.toString();
}
}
@Block() @Block()
public static class ElementDefinitionSlicingDiscriminatorComponent extends Element implements IBaseDatatypeElement { public static class ElementDefinitionSlicingDiscriminatorComponent extends Element implements IBaseDatatypeElement {
@ -1671,6 +1676,11 @@ public class ElementDefinition extends BackboneType implements ICompositeType {
} }
@Override
public String toString() {
return (type == null ? "??" : type.getCode()) + "="+(path == null ? "??" : path.asStringValue());
}
} }
@Block() @Block()

View File

@ -167,7 +167,7 @@ public class ElementWrappers {
Property family = b.getChildByName("family"); Property family = b.getChildByName("family");
Property given = wrapped.getChildByName("given"); Property given = wrapped.getChildByName("given");
String s = given != null && given.hasValues() ? given.getValues().get(0).primitiveValue() : ""; String s = given != null && given.hasValues() ? given.getValues().get(0).primitiveValue() : "";
if (family != null && family.hasValues()) if (family != null && family.hasValues() && family.getValues().get(0).primitiveValue() != null)
s = s + " " + family.getValues().get(0).primitiveValue().toUpperCase(); s = s + " " + family.getValues().get(0).primitiveValue().toUpperCase();
return s; return s;
} else { } else {

View File

@ -11,6 +11,13 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
public class ValidationProcessInfo { public class ValidationProcessInfo {
private TerminologyServiceErrorClass err; private TerminologyServiceErrorClass err;
private List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
public ValidationProcessInfo() {
}
public ValidationProcessInfo(List<OperationOutcomeIssueComponent> issues) {
this.issues = issues;
}
public TerminologyServiceErrorClass getErr() { public TerminologyServiceErrorClass getErr() {
return err; return err;
} }

View File

@ -100,6 +100,8 @@ public class ValueSetValidator {
private List<CodeSystem> localSystems = new ArrayList<>(); private List<CodeSystem> localSystems = new ArrayList<>();
Parameters expansionProfile; Parameters expansionProfile;
private TerminologyCapabilities txCaps; private TerminologyCapabilities txCaps;
private Set<String> unknownSystems;
private boolean throwToServer;
public ValueSetValidator(ValidationOptions options, ValueSet source, IWorkerContext context, Parameters expansionProfile, TerminologyCapabilities txCaps) { public ValueSetValidator(ValidationOptions options, ValueSet source, IWorkerContext context, Parameters expansionProfile, TerminologyCapabilities txCaps) {
this.valueset = source; this.valueset = source;
@ -120,6 +122,22 @@ public class ValueSetValidator {
analyseValueSet(); analyseValueSet();
} }
public Set<String> getUnknownSystems() {
return unknownSystems;
}
public void setUnknownSystems(Set<String> unknownSystems) {
this.unknownSystems = unknownSystems;
}
public boolean isThrowToServer() {
return throwToServer;
}
public void setThrowToServer(boolean throwToServer) {
this.throwToServer = throwToServer;
}
private void analyseValueSet() { private void analyseValueSet() {
if (localContext != null) { if (localContext != null) {
if (valueset != null) { if (valueset != null) {
@ -174,10 +192,16 @@ public class ValueSetValidator {
if (context.isNoTerminologyServer()) { if (context.isNoTerminologyServer()) {
if (c.hasVersion()) { if (c.hasVersion()) {
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, c.getSystem(), c.getVersion() , resolveCodeSystemVersions(c.getSystem()).toString()); String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, c.getSystem(), c.getVersion() , resolveCodeSystemVersions(c.getSystem()).toString());
res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)); if (valueSetDependsOn(c.getSystem(), c.getVersion())) {
unknownSystems.add(c.getSystem()+"|"+c.getVersion());
}
res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)).setUnknownSystems(unknownSystems);
} else { } else {
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, c.getSystem(), c.getVersion()); String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, c.getSystem(), c.getVersion());
res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)); if (valueSetDependsOn(c.getSystem(), null)) {
unknownSystems.add(c.getSystem());
}
res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)).setUnknownSystems(unknownSystems);
} }
} else { } else {
res = context.validateCode(options.withNoClient(), c, null); res = context.validateCode(options.withNoClient(), c, null);
@ -191,8 +215,9 @@ public class ValueSetValidator {
} }
} }
Coding foundCoding = null; Coding foundCoding = null;
String msg = null;
Boolean result = false;
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) { if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
Boolean result = false;
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(", "); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(", ");
for (Coding c : code.getCoding()) { for (Coding c : code.getCoding()) {
@ -212,11 +237,11 @@ public class ValueSetValidator {
} }
} }
if (result == null) { if (result == null) {
String msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), b.toString()); msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString());
info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path, msg)); info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, unknownSystems.isEmpty() ? IssueType.INVALID : IssueType.NOTFOUND, path, msg));
} else if (!result) { } else if (!result) {
String msg = context.formatMessagePlural(code.getCoding().size(), I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), b.toString()); msg = context.formatMessagePlural(code.getCoding().size(), I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString());
info.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg)); info.getIssues().addAll(makeIssue(IssueSeverity.ERROR, unknownSystems.isEmpty() ? IssueType.INVALID : IssueType.NOTFOUND, path, msg));
} }
} }
if (info.hasErrors()) { if (info.hasErrors()) {
@ -229,8 +254,11 @@ public class ValueSetValidator {
res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : ((CodeSystem) foundCoding.getUserData("cs")).getVersion()); res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : ((CodeSystem) foundCoding.getUserData("cs")).getVersion());
res.setDisplay(cd.getDisplay()); res.setDisplay(cd.getDisplay());
} }
res.setUnknownSystems(unknownSystems);
res.addCodeableConcept(vcc); res.addCodeableConcept(vcc);
return res; return res;
} else if (result == null) {
return new ValidationResult(IssueSeverity.WARNING, info.summary(), info.getIssues());
} else if (foundCoding == null) { } else if (foundCoding == null) {
return new ValidationResult(IssueSeverity.ERROR, "Internal Error that should not happen", makeIssue(IssueSeverity.FATAL, IssueType.EXCEPTION, path, "Internal Error that should not happen")); return new ValidationResult(IssueSeverity.ERROR, "Internal Error that should not happen", makeIssue(IssueSeverity.FATAL, IssueType.EXCEPTION, path, "Internal Error that should not happen"));
} else if (info.getIssues().size() > 0) { } else if (info.getIssues().size() > 0) {
@ -245,6 +273,15 @@ public class ValueSetValidator {
} }
} }
private boolean valueSetDependsOn(String system, String version) {
for (ConceptSetComponent inc : valueset.getCompose().getInclude()) {
if (system.equals(inc.getSystem()) && (version == null || inc.getVersion() == null || version.equals(inc.getVersion()))) {
return true;
}
}
return false;
}
private String getVersion(Coding c) { private String getVersion(Coding c) {
if (c.hasVersion()) { if (c.hasVersion()) {
return c.getVersion(); return c.getVersion();
@ -329,6 +366,7 @@ public class ValueSetValidator {
ValidationResult res = null; ValidationResult res = null;
boolean inExpansion = false; boolean inExpansion = false;
boolean inInclude = false; boolean inInclude = false;
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
VersionInfo vi = new VersionInfo(this); VersionInfo vi = new VersionInfo(this);
String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull(); String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull();
@ -363,8 +401,10 @@ public class ValueSetValidator {
if (cs == null) { if (cs == null) {
if (wv == null) { if (wv == null) {
warningMessage = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, system); warningMessage = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, system);
unknownSystems.add(system);
} else { } else {
warningMessage = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, system, wv, resolveCodeSystemVersions(system).toString()); warningMessage = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, system, wv, resolveCodeSystemVersions(system).toString());
unknownSystems.add(system+"|"+wv);
} }
if (!inExpansion) { if (!inExpansion) {
if (valueset != null && valueset.hasExpansion()) { if (valueset != null && valueset.hasExpansion()) {
@ -372,18 +412,18 @@ public class ValueSetValidator {
valueset.getUrl(), valueset.getUrl(),
code.getSystem(), code.getSystem(),
code.getCode().toString()); code.getCode().toString());
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path, msg)); issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path, msg));
throw new VSCheckerException(msg, issues); throw new VSCheckerException(msg, issues);
} else { } else {
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".system", warningMessage)); issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".system", warningMessage));
res = new ValidationResult(IssueSeverity.WARNING, warningMessage, issues);
if (valueset == null) { if (valueset == null) {
throw new VSCheckerException(warningMessage, issues); throw new VSCheckerException(warningMessage, issues);
} else { } else {
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), code.toString()); // String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), code.toString());
issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg)); // issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
throw new VSCheckerException(warningMessage+"; "+msg, issues); // we don't do this yet
// throw new VSCheckerException(warningMessage, issues);
} }
} }
} }
@ -407,7 +447,7 @@ public class ValueSetValidator {
// we'll take it on faith // we'll take it on faith
String disp = getPreferredDisplay(cc); String disp = getPreferredDisplay(cc);
res = new ValidationResult(system, cs.getVersion(), new ConceptDefinitionComponent().setCode(cc.getCode()).setDisplay(disp), disp); res = new ValidationResult(system, cs.getVersion(), new ConceptDefinitionComponent().setCode(cc.getCode()).setDisplay(disp), disp);
res.setMessage("Resolved system "+system+", but the definition is not complete, so assuming value set include is correct"); res.addToMessage("Resolved system "+system+", but the definition is not complete, so assuming value set include is correct");
return res; return res;
} }
} }
@ -419,12 +459,14 @@ public class ValueSetValidator {
// we just take the value set as face value then // we just take the value set as face value then
res = new ValidationResult(system, wv, new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay()), code.getDisplay()); res = new ValidationResult(system, wv, new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay()), code.getDisplay());
if (!preferServerSide(system)) { if (!preferServerSide(system)) {
res.setMessage("Code System unknown, so assuming value set expansion is correct ("+warningMessage+")"); res.addToMessage("Code System unknown, so assuming value set expansion is correct ("+warningMessage+")");
} }
} else { } else {
// well, we didn't find a code system - try the expansion? // well, we didn't find a code system - try the expansion?
// disabled waiting for discussion // disabled waiting for discussion
throw new FHIRException("No try the server"); if (throwToServer) {
throw new FHIRException("No; try the server");
}
} }
} else { } else {
inExpansion = checkExpansion(code, vi); inExpansion = checkExpansion(code, vi);
@ -432,7 +474,7 @@ public class ValueSetValidator {
} }
String wv = vi.getVersion(system, code.getVersion()); String wv = vi.getVersion(system, code.getVersion());
ValidationProcessInfo info = new ValidationProcessInfo(); ValidationProcessInfo info = new ValidationProcessInfo(issues);
// then, if we have a value set, we check it's in the value set // then, if we have a value set, we check it's in the value set
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) { if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
@ -446,20 +488,24 @@ public class ValueSetValidator {
res.setErrorClass(info.getErr()); res.setErrorClass(info.getErr());
} }
if (ok == null) { if (ok == null) {
res.setMessage("Unable to check whether code is in value set "+valueset.getUrl()+": "+info.summary()).setSeverity(IssueSeverity.WARNING); String m = "Unable to check whether the code is in the value set "+valueset.getVersionedUrl();
res.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.EXCEPTION, path, res.getMessage())); res.addToMessage(m);
res.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.NOTFOUND, path, m));
res.setUnknownSystems(unknownSystems);
res.setSeverity(IssueSeverity.ERROR); // back patching for display logic issue
} else if (!inExpansion && !inInclude) { } else if (!inExpansion && !inInclude) {
if (!info.getIssues().isEmpty()) { // if (!info.getIssues().isEmpty()) {
res.setMessage("Not in value set "+valueset.getUrl()+": "+info.summary()).setSeverity(IssueSeverity.ERROR); // res.setMessage("Not in value set "+valueset.getUrl()+": "+info.summary()).setSeverity(IssueSeverity.ERROR);
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, res.getMessage())); // res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, res.getMessage()));
} else { // } else
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), code.toString()); // {
res.setMessage(msg).setSeverity(IssueSeverity.ERROR); String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), code.toString());
res.addToMessage(msg).setSeverity(IssueSeverity.ERROR);
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg)); res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
res.setDefinition(null); res.setDefinition(null);
res.setSystem(null); res.setSystem(null);
res.setDisplay(null); res.setDisplay(null);
} // }
} else if (warningMessage!=null) { } else if (warningMessage!=null) {
String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage); String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage);
res = new ValidationResult(IssueSeverity.WARNING, msg, makeIssue(IssueSeverity.WARNING, IssueType.EXCEPTION, path, msg)); res = new ValidationResult(IssueSeverity.WARNING, msg, makeIssue(IssueSeverity.WARNING, IssueType.EXCEPTION, path, msg));
@ -472,7 +518,7 @@ public class ValueSetValidator {
} }
} }
} else if ((res != null && !res.isOk())) { } else if ((res != null && !res.isOk())) {
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), code.toString()); String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), code.toString());
res.setMessage(res.getMessage()+"; "+msg); res.setMessage(res.getMessage()+"; "+msg);
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg)); res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
} }
@ -483,7 +529,7 @@ public class ValueSetValidator {
return res; return res;
} }
private static final HashSet<String> SERVER_SIDE_LIST = new HashSet<>(Arrays.asList("http://fdasis.nlm.nih.gov", "http://hl7.org/fhir/sid/ndc", "http://loinc.org", "http://snomed.info/sct", "http://unitsofmeasure.org", private static final Set<String> SERVER_SIDE_LIST = new HashSet<>(Arrays.asList("http://fdasis.nlm.nih.gov", "http://hl7.org/fhir/sid/ndc", "http://loinc.org", "http://snomed.info/sct", "http://unitsofmeasure.org",
"http://unstats.un.org/unsd/methods/m49/m49.htm", "http://varnomen.hgvs.org", "http://www.nlm.nih.gov/research/umls/rxnorm", "https://www.usps.com/", "http://unstats.un.org/unsd/methods/m49/m49.htm", "http://varnomen.hgvs.org", "http://www.nlm.nih.gov/research/umls/rxnorm", "https://www.usps.com/",
"urn:ietf:bcp:13","urn:ietf:bcp:47","urn:ietf:rfc:3986", "urn:iso:std:iso:3166","urn:iso:std:iso:4217", "urn:oid:1.2.36.1.2001.1005.17")); "urn:ietf:bcp:13","urn:ietf:bcp:47","urn:ietf:rfc:3986", "urn:iso:std:iso:3166","urn:iso:std:iso:4217", "urn:oid:1.2.36.1.2001.1005.17"));
@ -917,6 +963,7 @@ public class ValueSetValidator {
public Boolean codeInValueSet(String system, String version, String code, ValidationProcessInfo info) throws FHIRException { public Boolean codeInValueSet(String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
return codeInValueSet("code", system, version, code, info); return codeInValueSet("code", system, version, code, info);
} }
public Boolean codeInValueSet(String path, String system, String version, String code, ValidationProcessInfo info) throws FHIRException { public Boolean codeInValueSet(String path, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
if (valueset == null) { if (valueset == null) {
return false; return false;
@ -991,30 +1038,42 @@ public class ValueSetValidator {
// ok, we need the code system // ok, we need the code system
CodeSystem cs = resolveCodeSystem(system, version); CodeSystem cs = resolveCodeSystem(system, version);
if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) { if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) {
// make up a transient value set with if (throwToServer) {
ValueSet vs = new ValueSet(); // make up a transient value set with
vs.setStatus(PublicationStatus.ACTIVE); ValueSet vs = new ValueSet();
vs.setUrl(valueset.getUrl()+"--"+vsiIndex); vs.setStatus(PublicationStatus.ACTIVE);
vs.setVersion(valueset.getVersion()); vs.setUrl(valueset.getUrl()+"--"+vsiIndex);
vs.getCompose().addInclude(vsi); vs.setVersion(valueset.getVersion());
ValidationResult res = context.validateCode(options.withNoClient(), new Coding(system, code, null), vs); vs.getCompose().addInclude(vsi);
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) { ValidationResult res = context.validateCode(options.withNoClient(), new Coding(system, code, null), vs);
if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) { if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
// server didn't know the code system either - we'll take it face value if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system))); // server didn't know the code system either - we'll take it face value
for (ConceptReferenceComponent cc : vsi.getConcept()) { info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system)));
if (cc.getCode().equals(code)) { for (ConceptReferenceComponent cc : vsi.getConcept()) {
return true; if (cc.getCode().equals(code)) {
return true;
}
} }
info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED);
return null;
} }
info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED); return false;
} }
return false; if (res.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
throw new NoTerminologyServiceException();
}
return res.isOk();
} else {
if (unknownSystems != null) {
if (version == null) {
unknownSystems.add(system);
} else {
unknownSystems.add(system+"|"+version);
}
}
return null;
} }
if (res.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
throw new NoTerminologyServiceException();
}
return res.isOk();
} else { } else {
if (vsi.hasFilter()) { if (vsi.hasFilter()) {
ok = true; ok = true;

View File

@ -100,7 +100,7 @@ public interface IResourceValidator {
void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars); void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars);
boolean isForPublication(); boolean isForPublication();
void setForPublication(boolean forPublication); IResourceValidator setForPublication(boolean forPublication);
/** /**
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning * Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning

View File

@ -585,8 +585,8 @@ public class SnapShotGenerationTests {
boolean structureDefinitionEquality = t1.equalsDeep(t2); boolean structureDefinitionEquality = t1.equalsDeep(t2);
if (!structureDefinitionEquality) { if (!structureDefinitionEquality) {
System.out.println("Encountered unexpected diff in structure definition"); System.out.println("Encountered unexpected change in diff in structure definition");
DiffUtils.testDiff(dst.getAbsolutePath(), actualFilePath); // DiffUtils.testDiff(dst.getAbsolutePath(), actualFilePath);
} }
Assertions.assertTrue(structureDefinitionEquality, "Output does not match expected"); Assertions.assertTrue(structureDefinitionEquality, "Output does not match expected");
} }

View File

@ -590,7 +590,7 @@ public class Utilities {
public static boolean isPlural(String word) { public static boolean isPlural(String word) {
word = word.toLowerCase(); word = word.toLowerCase();
if ("restricts".equals(word) || "contains".equals(word) || "data".equals(word) || "specimen".equals(word) || "replaces".equals(word) || "addresses".equals(word) if ("restricts".equals(word) || "contains".equals(word) || "data".equals(word) || "specimen".equals(word) || "replaces".equals(word) || "addresses".equals(word)
|| "supplementalData".equals(word) || "instantiates".equals(word) || "imports".equals(word)) || "supplementalData".equals(word) || "instantiates".equals(word) || "imports".equals(word) || "covers".equals(word))
return false; return false;
Inflector inf = new Inflector(); Inflector inf = new Inflector();
return !inf.singularize(word).equals(word); return !inf.singularize(word).equals(word);
@ -1966,4 +1966,8 @@ public class Utilities {
return Utilities.startsWithInList(s.replace("https://", "http://"), FhirSettings.getTxFhirProduction(), FhirSettings.getTxFhirDevelopment(), FhirSettings.getTxFhirLocal()); return Utilities.startsWithInList(s.replace("https://", "http://"), FhirSettings.getTxFhirProduction(), FhirSettings.getTxFhirDevelopment(), FhirSettings.getTxFhirLocal());
} }
public static String[] splitLines(String txt) {
return txt.split("\\r?\\n|\\r");
}
} }

View File

@ -866,6 +866,9 @@ public class I18nConstants {
public static final String SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION = "SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION"; public static final String SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION = "SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION";
public static final String SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE = "SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE"; public static final String SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE = "SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE";
public static final String SM_TARGET_TRANSFORM_OP_INVALID_TYPE = "SM_TARGET_TRANSFORM_OP_INVALID_TYPE"; public static final String SM_TARGET_TRANSFORM_OP_INVALID_TYPE = "SM_TARGET_TRANSFORM_OP_INVALID_TYPE";
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";
} }

View File

@ -672,7 +672,7 @@ RENDER_BUNDLE_DOCUMENT_CONTENT = Additional Document Content
RENDER_BUNDLE_HEADER_DOC_ENTRY_URD = {0}. {1} ({2}/{3}) RENDER_BUNDLE_HEADER_DOC_ENTRY_URD = {0}. {1} ({2}/{3})
RENDER_BUNDLE_HEADER_DOC_ENTRY_U = {0}. {1} RENDER_BUNDLE_HEADER_DOC_ENTRY_U = {0}. {1}
RENDER_BUNDLE_HEADER_DOC_ENTRY_RD = {0}. {2}/{3} RENDER_BUNDLE_HEADER_DOC_ENTRY_RD = {0}. {2}/{3}
UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = Unable to determine whether the provided codes {1} are in the value set {0} because the value set or a code system it depends on is not known to the validator UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = Unable to check whether the code is in the value set {0}
TERMINOLOGY_TX_SYSTEM_WRONG_HTML = The code system reference {0} is wrong - the code system reference cannot be to an HTML page. This may be the correct reference: {1} TERMINOLOGY_TX_SYSTEM_WRONG_HTML = The code system reference {0} is wrong - the code system reference cannot be to an HTML page. This may be the correct reference: {1}
TERMINOLOGY_TX_SYSTEM_WRONG_BUILD = The code system reference {0} is wrong - the code system reference cannot be a reference to build.fhir.org. This may be the correct reference: {1} TERMINOLOGY_TX_SYSTEM_WRONG_BUILD = The code system reference {0} is wrong - the code system reference cannot be a reference to build.fhir.org. This may be the correct reference: {1}
FHIRPATH_BAD_DATE = Unable to parse Date {0} FHIRPATH_BAD_DATE = Unable to parse Date {0}
@ -920,6 +920,7 @@ NO_VALID_DISPLAY_FOUND_other = No valid Display Names found for {1}#{2} in the l
SD_NO_CONTEXT_WHEN_NOT_EXTENSION = The type is {0} so an extension context should not be specified SD_NO_CONTEXT_WHEN_NOT_EXTENSION = The type is {0} so an extension context should not be specified
SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION = The type is {0} so an extension context invariants should not be specified SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION = The type is {0} so an extension context invariants should not be specified
SD_CONTEXT_SHOULD_NOT_BE_ELEMENT = Review the extension type: extensions should not have a context of {0} unless it''s really intended that they can be used anywhere SD_CONTEXT_SHOULD_NOT_BE_ELEMENT = Review the extension type: extensions should not have a context of {0} unless it''s really intended that they can be used anywhere
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

View File

@ -156,6 +156,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
private ValidationLevel level = ValidationLevel.HINTS; private ValidationLevel level = ValidationLevel.HINTS;
protected Coding jurisdiction; protected Coding jurisdiction;
protected boolean allowExamples; protected boolean allowExamples;
protected boolean forPublication;
public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager) { public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager) {
super(); super();
@ -1243,6 +1244,15 @@ public class BaseValidator implements IValidationContextResourceLoader {
protected boolean isExampleUrl(String url) { protected boolean isExampleUrl(String url) {
return Utilities.containsInList(url, "example.org", "acme.com", "acme.org"); return Utilities.containsInList(url, "example.org", "acme.com", "acme.org");
} }
public boolean isForPublication() {
return forPublication;
}
public BaseValidator setForPublication(boolean forPublication) {
this.forPublication = forPublication;
return this;
}
} }

View File

@ -505,7 +505,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private ValidationOptions baseOptions = new ValidationOptions(); private ValidationOptions baseOptions = new ValidationOptions();
private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>(); private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>();
private boolean logProgress; private boolean logProgress;
private boolean forPublication;
public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices, XVerExtensionManager xverManager) { public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices, XVerExtensionManager xverManager) {
super(theContext, xverManager); super(theContext, xverManager);
@ -2394,18 +2393,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
if (type.equals("dateTime")) { if (type.equals("dateTime")) {
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue()); boolean dok = ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue()
e.primitiveValue() .matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, "'"+e.primitiveValue()+"' doesn't meet format requirements for dateTime") && ok;
.matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, e.primitiveValue()) && ok; dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !hasTime(e.primitiveValue()) || hasTimeZone(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_TZ) && dok;
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !hasTime(e.primitiveValue()) || hasTimeZone(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_TZ) && ok; dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && dok;
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && ok; if (dok) {
try { try {
DateTimeType dt = new DateTimeType(e.primitiveValue()); DateTimeType dt = new DateTimeType(e.primitiveValue());
} catch (Exception ex) { warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, ex.getMessage()); } catch (Exception ex) {
ok = false; rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, ex.getMessage());
dok = false;
}
} }
ok = ok && dok;
} }
if (type.equals("time")) { if (type.equals("time")) {
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
@ -2419,15 +2421,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
if (type.equals("date")) { if (type.equals("date")) {
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue()); boolean dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue().matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATE_VALID, "'"+e.primitiveValue()+"' doesn't meet format requirements for date");
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue().matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATE_VALID) && ok; dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && dok;
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && ok; if (dok) {
try { try {
DateType dt = new DateType(e.primitiveValue()); DateType dt = new DateType(e.primitiveValue());
} catch (Exception ex) { warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATE_VALID, ex.getMessage()); } catch (Exception ex) {
ok = false; rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATE_VALID, ex.getMessage());
dok = false;
}
} }
ok = ok && dok;
} }
if (type.equals("base64Binary")) { if (type.equals("base64Binary")) {
String encoded = e.primitiveValue(); String encoded = e.primitiveValue();
@ -2511,15 +2516,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
if (type.equals("instant")) { if (type.equals("instant")) {
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, boolean dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
e.primitiveValue().matches("-?[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REGEX, e.primitiveValue()) && ok; e.primitiveValue().matches("-?[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REGEX, "'"+e.primitiveValue()+"' doesn't meet format requirements for instant)");
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue()); if (dok) {
try { try {
InstantType dt = new InstantType(e.primitiveValue()); InstantType dt = new InstantType(e.primitiveValue());
} catch (Exception ex) { warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INSTANT_VALID, ex.getMessage()); } catch (Exception ex) {
ok = false; rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INSTANT_VALID, ex.getMessage());
dok = false;
}
} }
ok = ok && dok;
} }
if (type.equals("code") && e.primitiveValue() != null) { if (type.equals("code") && e.primitiveValue() != null) {
@ -5040,7 +5048,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else if (element.getType().equals("SearchParameter")) { } else if (element.getType().equals("SearchParameter")) {
return new SearchParameterValidator(context, timeTracker, fpe, xverManager, jurisdiction).validateSearchParameter(errors, element, stack); return new SearchParameterValidator(context, timeTracker, fpe, xverManager, jurisdiction).validateSearchParameter(errors, element, stack);
} else if (element.getType().equals("StructureDefinition")) { } else if (element.getType().equals("StructureDefinition")) {
return new StructureDefinitionValidator(context, timeTracker, fpe, wantCheckSnapshotUnchanged, xverManager, jurisdiction).validateStructureDefinition(errors, element, stack); return new StructureDefinitionValidator(context, timeTracker, fpe, wantCheckSnapshotUnchanged, xverManager, jurisdiction, forPublication).validateStructureDefinition(errors, element, stack);
} else if (element.getType().equals("StructureMap")) { } else if (element.getType().equals("StructureMap")) {
return new StructureMapValidator(context, timeTracker, fpe, xverManager,profileUtilities, jurisdiction).validateStructureMap(errors, element, stack); return new StructureMapValidator(context, timeTracker, fpe, xverManager,profileUtilities, jurisdiction).validateStructureMap(errors, element, stack);
} else if (element.getType().equals("ValueSet")) { } else if (element.getType().equals("ValueSet")) {
@ -6527,14 +6535,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
this.logProgress = logProgress; this.logProgress = logProgress;
} }
public boolean isForPublication() {
return forPublication;
}
public void setForPublication(boolean forPublication) {
this.forPublication = forPublication;
}
public boolean isDisplayWarnings() { public boolean isDisplayWarnings() {
return baseOptions.isDisplayWarningMode(); return baseOptions.isDisplayWarningMode();
} }
@ -6543,4 +6543,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
baseOptions.setDisplayWarningMode(displayWarnings); baseOptions.setDisplayWarningMode(displayWarnings);
} }
public InstanceValidator setForPublication(boolean forPublication) {
this.forPublication = forPublication;
return this;
}
} }

View File

@ -60,13 +60,14 @@ public class StructureDefinitionValidator extends BaseValidator {
private FHIRPathEngine fpe; private FHIRPathEngine fpe;
private boolean wantCheckSnapshotUnchanged; private boolean wantCheckSnapshotUnchanged;
public StructureDefinitionValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, boolean wantCheckSnapshotUnchanged, XVerExtensionManager xverManager, Coding jurisdiction) { public StructureDefinitionValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, boolean wantCheckSnapshotUnchanged, XVerExtensionManager xverManager, Coding jurisdiction, boolean forPublication) {
super(context, xverManager); super(context, xverManager);
source = Source.InstanceValidator; source = Source.InstanceValidator;
this.fpe = fpe; this.fpe = fpe;
this.timeTracker = timeTracker; this.timeTracker = timeTracker;
this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged; this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged;
this.jurisdiction = jurisdiction; this.jurisdiction = jurisdiction;
this.forPublication = forPublication;
} }
public boolean validateStructureDefinition(List<ValidationMessage> errors, Element src, NodeStack stack) { public boolean validateStructureDefinition(List<ValidationMessage> errors, Element src, NodeStack stack) {
@ -89,6 +90,7 @@ public class StructureDefinitionValidator extends BaseValidator {
rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasType() && sd.getType().equals(base.getType()), I18nConstants.SD_CONSTRAINED_TYPE_NO_MATCH, sd.getType(), base.getType()); rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasType() && sd.getType().equals(base.getType()), I18nConstants.SD_CONSTRAINED_TYPE_NO_MATCH, sd.getType(), base.getType());
List<ValidationMessage> msgs = new ArrayList<>(); List<ValidationMessage> msgs = new ArrayList<>();
ProfileUtilities pu = new ProfileUtilities(context, msgs, null); ProfileUtilities pu = new ProfileUtilities(context, msgs, null);
pu.setForPublication(forPublication);
pu.setXver(xverManager); pu.setXver(xverManager);
pu.setNewSlicingProcessing(!sd.hasFhirVersion() || VersionUtilities.isR4Plus(sd.getFhirVersion().toCode())); pu.setNewSlicingProcessing(!sd.hasFhirVersion() || VersionUtilities.isR4Plus(sd.getFhirVersion().toCode()));
pu.generateSnapshot(base, sd, sd.getUrl(), "http://hl7.org/fhir/R4/", sd.getName()); pu.generateSnapshot(base, sd, sd.getUrl(), "http://hl7.org/fhir/R4/", sd.getName());
@ -121,7 +123,7 @@ public class StructureDefinitionValidator extends BaseValidator {
I18nConstants.SD_DERIVATION_KIND_MISMATCH, base.getKindElement().primitiveValue(), src.getChildValue("kind")) && ok; I18nConstants.SD_DERIVATION_KIND_MISMATCH, base.getKindElement().primitiveValue(), src.getChildValue("kind")) && ok;
} }
} }
} catch (FHIRException | IOException e) { } catch (Exception e) {
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage()); rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
ok = false; ok = false;
} }

View File

@ -175,19 +175,19 @@ public class SnapShotGenerationXTests {
} }
public void load(String version) throws FHIRFormatError, FileNotFoundException, IOException { public void load(String version) throws FHIRFormatError, FileNotFoundException, IOException {
if (UtilitiesXTests.findTestResource("rX", "snapshot-generation", id + "-input.json")) if (TestingUtilities.findTestResource("rX", "snapshot-generation", id + "-input.json"))
source = (StructureDefinition) XVersionLoader.loadJson(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", id + "-input.json")); source = (StructureDefinition) XVersionLoader.loadJson(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-input.json"));
else else
source = (StructureDefinition) XVersionLoader.loadXml(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", id + "-input.xml")); source = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-input.xml"));
if (!fail) if (!fail)
expected = (StructureDefinition) XVersionLoader.loadXml(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", id + "-expected.xml")); expected = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-expected.xml"));
if (!Utilities.noString(include)) if (!Utilities.noString(include))
included = (StructureDefinition) XVersionLoader.loadXml(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", include + ".xml")); included = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", include + ".xml"));
if (!Utilities.noString(register)) { if (!Utilities.noString(register)) {
if (UtilitiesXTests.findTestResource("rX", "snapshot-generation", register + ".xml")) { if (TestingUtilities.findTestResource("rX", "snapshot-generation", register + ".xml")) {
included = (StructureDefinition) XVersionLoader.loadXml(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", register + ".xml")); included = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", register + ".xml"));
} else { } else {
included = (StructureDefinition) XVersionLoader.loadJson(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", register + ".json")); included = (StructureDefinition) XVersionLoader.loadJson(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", register + ".json"));
} }
} }
} }
@ -404,7 +404,7 @@ public class SnapShotGenerationXTests {
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException { public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException {
SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext(); SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext();
Document tests = XMLUtil.parseToDom(UtilitiesXTests.loadTestResource("rX", "snapshot-generation", "manifest.xml")); Document tests = XMLUtil.parseToDom(TestingUtilities.loadTestResource("rX", "snapshot-generation", "manifest.xml"));
Element test = XMLUtil.getFirstChild(tests.getDocumentElement()); Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
List<Object[]> objects = new ArrayList<Object[]>(); List<Object[]> objects = new ArrayList<Object[]>();
while (test != null && test.getNodeName().equals("test")) { while (test != null && test.getNodeName().equals("test")) {
@ -471,7 +471,7 @@ public class SnapShotGenerationXTests {
pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors, false); pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors, false);
if (!errors.isEmpty()) if (!errors.isEmpty())
throw new FHIRException(errors.get(0)); throw new FHIRException(errors.get(0));
IOUtils.copy(UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", test.getId() + "-expected.xml"), new FileOutputStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-expected.xml"))); 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() + "-actual.xml")), test.getOutput());
Assertions.assertTrue(test.expected.equalsDeep(test.output), "Output does not match expected"); Assertions.assertTrue(test.expected.equalsDeep(test.output), "Output does not match expected");
} }
@ -545,7 +545,7 @@ public class SnapShotGenerationXTests {
File dst = new File(UtilitiesXTests.tempFile("snapshot", test.getId() + "-expected.xml")); File dst = new File(UtilitiesXTests.tempFile("snapshot", test.getId() + "-expected.xml"));
if (dst.exists()) if (dst.exists())
dst.delete(); dst.delete();
IOUtils.copy(UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", test.getId() + "-expected.xml"), new FileOutputStream(dst)); 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() + "-actual.xml")), output);
StructureDefinition t1 = test.expected.copy(); StructureDefinition t1 = test.expected.copy();
t1.setText(null); t1.setText(null);

View File

@ -280,6 +280,11 @@ public class TerminologyServiceTests {
if (vm.getCodeableConcept() != null) { if (vm.getCodeableConcept() != null) {
res.addParameter("codeableConcept", vm.getCodeableConcept()); res.addParameter("codeableConcept", vm.getCodeableConcept());
} }
if (vm.getUnknownSystems() != null) {
for (String s : vm.getUnknownSystems()) {
res.addParameter("x-caused-by-unknown-system", new UriType(s));
}
}
if (vm.getIssues().size() > 0) { if (vm.getIssues().size() > 0) {
OperationOutcome oo = new OperationOutcome(); OperationOutcome oo = new OperationOutcome();
oo.getIssue().addAll(vm.getIssues()); oo.getIssue().addAll(vm.getIssues());

View File

@ -202,6 +202,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
byte[] testCaseContent = TestingUtilities.loadTestResource("validator", JsonUtilities.str(content, "file")).getBytes(StandardCharsets.UTF_8); byte[] testCaseContent = TestingUtilities.loadTestResource("validator", JsonUtilities.str(content, "file")).getBytes(StandardCharsets.UTF_8);
// load and process content // load and process content
FhirFormat fmt = determineFormat(content, testCaseContent); FhirFormat fmt = determineFormat(content, testCaseContent);
if (fmt == null) {
throw new FHIRException("Unknown format in source "+JsonUtilities.str(content, "file"));
}
InstanceValidator val = vCurr.getValidator(fmt); InstanceValidator val = vCurr.getValidator(fmt);
val.setWantCheckSnapshotUnchanged(true); val.setWantCheckSnapshotUnchanged(true);
@ -238,6 +241,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
val.setValidationLanguage(content.get("language").getAsString()); val.setValidationLanguage(content.get("language").getAsString());
else else
val.setValidationLanguage(null); val.setValidationLanguage(null);
val.setForPublication(content.has("for-publication") && "true".equals(content.get("for-publication").getAsString()));
if (content.has("default-version")) { if (content.has("default-version")) {
val.setBaseOptions(val.getBaseOptions().withVersionFlexible(content.get("default-version").getAsBoolean())); val.setBaseOptions(val.getBaseOptions().withVersionFlexible(content.get("default-version").getAsBoolean()));
} else { } else {

View File

@ -1116,3 +1116,39 @@ v: {
"class" : "UNKNOWN" "class" : "UNKNOWN"
} }
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "77176002",
"display" : "Smoker"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-bloodGroup", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Smoker",
"code" : "77176002",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "38341003",
"display" : "Hypertensive disorder, systemic arterial (disorder)"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-bloodGroup", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "High blood pressure",
"code" : "38341003",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------

View File

@ -63,3 +63,35 @@ v: {
"class" : "SERVER_ERROR" "class" : "SERVER_ERROR"
} }
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
{"code" : {
"system" : "http://varnomen.hgvs.org",
"code" : "NC_000019.8:g.1171707G>A"
}, "url": "http://hl7.org/fhir/us/mcode/ValueSet/mcode-hgvs-vs", "version": "1.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "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 from server: Error parsing HGVS response: Error parsing JSON source: Unexpected char \"<\" in json stream at Line 0 (path=[])",
"class" : "SERVER_ERROR"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://varnomen.hgvs.org",
"code" : "NC_000019.8:g.1171707G>AXXX"
}, "url": "http://hl7.org/fhir/us/mcode/ValueSet/mcode-hgvs-vs", "version": "1.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "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 from server: Error parsing HGVS response: Error parsing JSON source: Unexpected char \"<\" in json stream at Line 0 (path=[])",
"class" : "SERVER_ERROR"
}
-------------------------------------------------------------------------------------

View File

@ -3167,3 +3167,279 @@ v: {
"version" : "2.74" "version" : "2.74"
} }
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://loinc.org",
"code" : "59408-5",
"display" : "O2 % BldC Oximetry"
},
{
"system" : "http://loinc.org",
"code" : "2708-6",
"display" : "Oxygen saturation in Arterial blood"
}]
}, "url": "http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs", "version": "4.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"CHECK_MEMERSHIP_ONLY", "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" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5 - should be one of 26 choices: 'Oxygen saturation in Arterial blood by Pulse oximetry, \"SaO2 % BldA PulseOx\", \"O2 SaO2\" (pl-PL), \"saturacja krwi tlenem\" (pl-PL), \"MFr O2\" (zh-CN), \"tO2\" (zh-CN), \"总氧\" (zh-CN), \"氧气 SaO2 动脉血 动脉血O2饱和度 可用数量表示的\" (zh-CN), \"定量性\" (zh-CN), \"数值型\" (zh-CN), \"数量型\" (zh-CN), \"连续数值型标尺 时刻\" (zh-CN), \"随机\" (zh-CN), \"随意\" (zh-CN), \"瞬间 肺部测量指标与呼吸机管理 脉搏血氧测定法\" (zh-CN), \"脉搏血氧定量\" (zh-CN), \"脉搏血氧测定\" (zh-CN), \"脉搏血氧仪 血氧测定法 饱和 饱和状态 饱和程度\" (zh-CN), \"O2-Sättigung\" (de-DE), \"Frazione di massa Gestione ventilazione polmonare Punto nel tempo (episodio) Sangue arterioso\" (it-IT), \"Oksijen doymuşluğu\" (tr-TR), \"Количественный Кровь артериальная Массовая доля Насыщение кислородом Оксигемометрия\" (ru-RU), \"Гемоксиметрия Точка во времени\" (ru-RU), \"Момент\" (ru-RU), \"zuurstofsaturatiemeting\" (nl-NL), \"O2 SatO2\" (fr-BE)' for the language(s) '--' (from Tx-Server)",
"class" : "UNKNOWN"
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://loinc.org",
"code" : "3150-0",
"display" : "Inhaled Oxygen Concentration"
}]
}, "url": "http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs", "version": "4.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"CHECK_MEMERSHIP_ONLY", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Inhaled oxygen concentration",
"code" : "3150-0",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://loinc.org",
"code" : "3151-8",
"display" : "Flow Rate"
}]
}, "url": "http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs", "version": "4.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"CHECK_MEMERSHIP_ONLY", "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" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8 - should be one of 37 choices: 'Inhaled oxygen flow rate, \"Inhaled O2 flow rate\", \"O2\" (zh-CN), \"tO2\" (zh-CN), \"总氧\" (zh-CN), \"氧气 体积速率(单位时间)\" (zh-CN), \"单位时间内体积的变化速率\" (zh-CN), \"流量 可用数量表示的\" (zh-CN), \"定量性\" (zh-CN), \"数值型\" (zh-CN), \"数量型\" (zh-CN), \"连续数值型标尺 吸入气\" (zh-CN), \"吸入气体\" (zh-CN), \"吸入的空气 所吸入的氧\" (zh-CN), \"已吸入的氧气 时刻\" (zh-CN), \"随机\" (zh-CN), \"随意\" (zh-CN), \"瞬间 气 气体类 空气\" (zh-CN), \"Inhaled O2\" (pt-BR), \"vRate\" (pt-BR), \"Volume rate\" (pt-BR), \"Flow\" (pt-BR), \"Point in time\" (pt-BR), \"Random\" (pt-BR), \"IhG\" (pt-BR), \"Inhaled Gas\" (pt-BR), \"Inspired\" (pt-BR), \"Quantitative\" (pt-BR), \"QNT\" (pt-BR), \"Quant\" (pt-BR), \"Quan\" (pt-BR), \"Gases\" (pt-BR), \"Clinico Gas inalati Punto nel tempo (episodio) Tasso di Volume\" (it-IT), \"Количественный Объемная скорость Точка во времени\" (ru-RU), \"Момент\" (ru-RU), \"ingeademde O2\" (nl-NL), \"O2-Zufuhr\" (de-AT)' for the language(s) '--' (from Tx-Server)",
"class" : "UNKNOWN"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "883-9",
"display" : "ABO group [Type] in Blood"
}, "url": "http://hl7.org/fhir/ValueSet/observation-vitalsignresult", "version": "4.0.1", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "ABO group [Type] in Blood",
"code" : "883-9",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "883-9"
}, "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" : "ABO group [Type] in Blood",
"code" : "883-9",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "46418-0",
"display" : "INR in Capillary blood by Coagulation assay"
}, "url": "http://hl7.org/fhir/ValueSet/observation-vitalsignresult", "version": "4.0.1", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "INR in Capillary blood by Coagulation assay",
"code" : "46418-0",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "77140-2",
"display" : "Creatinine [Moles/volume] in Serum, Plasma or Blood"
}, "url": "http://hl7.org/fhir/ValueSet/observation-vitalsignresult", "version": "4.0.1", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Creatinine [Moles/volume] in Serum, Plasma or Blood",
"code" : "77140-2",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "4535-1",
"display" : "Cytotoxic percent reactive Ab [Presence] in Serum by Quick method"
}, "url": "http://hl7.org/fhir/ValueSet/observation-vitalsignresult", "version": "4.0.1", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Cytotoxic percent reactive Ab [Presence] in Serum by Quick method",
"code" : "4535-1",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "29463-7",
"display" : "Body weight"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "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"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "8302-2",
"display" : "Body height"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "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 height",
"code" : "8302-2",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "39156-5",
"display" : "Body mass index (BMI) [Ratio]"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "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 mass index (BMI) [Ratio]",
"code" : "39156-5",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "85354-9",
"display" : "Blood pressure panel with all children optional"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Blood pressure panel with all children optional",
"code" : "85354-9",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "883-9",
"display" : "ABO group [Type] in Blood"
}, "url": "https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory", "version": "0.5.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "ABO group [Type] in Blood",
"code" : "883-9",
"system" : "http://loinc.org",
"version" : "2.74"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "X-34133-9"
}, "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" : "Unknown Code 'X-34133-9' in the system 'http://loinc.org'; The provided code http://loinc.org#X-34133-9 is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)",
"class" : "UNKNOWN"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "5792-7"
}, "valueSet" :{
"resourceType" : "ValueSet"
}, "langs":"[]", "useServer":"true", "useClient":"false", "guessSystem":"false", "valueSetMode":"CHECK_MEMERSHIP_ONLY", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"severity" : "error",
"error" : "Error from server: Unable to resolve value set \"http://hl7.org/fhir/ValueSet/birthDate\"",
"class" : "SERVER_ERROR"
}
-------------------------------------------------------------------------------------

View File

@ -2116,3 +2116,37 @@ v: {
"class" : "UNKNOWN" "class" : "UNKNOWN"
} }
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "77176002"
}, "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" : "Smoker",
"code" : "77176002",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "38341003"
}, "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" : "High blood pressure",
"code" : "38341003",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------

View File

@ -0,0 +1,19 @@
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://dicom.nema.org/resources/ontology/DCM",
"code" : "110122",
"display" : "Login"
}, "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" : "Login",
"code" : "110122",
"system" : "http://dicom.nema.org/resources/ontology/DCM",
"version" : "2023.1.20230123"
}
-------------------------------------------------------------------------------------

View File

@ -752,3 +752,73 @@ v: {
"version" : "http://snomed.info/sct/900000000000207008/version/20230131" "version" : "http://snomed.info/sct/900000000000207008/version/20230131"
} }
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "90655003",
"display" : "Geriatrics specialist"
}, "url": "http://hl7.org/fhir/ValueSet/c80-practice-codes", "version": "5.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Geriatrics specialist",
"code" : "90655003",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "90655003"
}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Geriatrics specialist",
"code" : "90655003",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "106004",
"display" : "Posterior carpal region"
}, "url": "http://hl7.org/fhir/ValueSet/clinical-findings", "version": "5.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Posterior carpal region",
"code" : "106004",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "106004"
}, "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" : "Posterior carpal region",
"code" : "106004",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20230131"
}
-------------------------------------------------------------------------------------

View File

@ -19,7 +19,7 @@
<properties> <properties>
<hapi_fhir_version>6.4.1</hapi_fhir_version> <hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.3.6</validator_test_case_version> <validator_test_case_version>1.3.7-SNAPSHOT</validator_test_case_version>
<jackson_version>2.14.0</jackson_version> <jackson_version>2.14.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version> <junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version> <junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>