Merge pull request #1268 from hapifhir/gg-202304-snapshot-fixes
Gg 202304 snapshot fixes
This commit is contained in:
commit
bd49a13d6d
|
@ -1,7 +1,12 @@
|
|||
## 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
|
||||
|
||||
* no changes
|
||||
* Add support for R4B to loader
|
||||
|
|
|
@ -75,6 +75,8 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader {
|
|||
protected BaseLoaderR5 loaderFactory(NpmPackage npm) throws JsonSyntaxException, IOException {
|
||||
if (VersionUtilities.isR5Plus(npm.fhirVersion())) {
|
||||
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())) {
|
||||
return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.version());
|
||||
} else if (VersionUtilities.isR3Ver(npm.fhirVersion())) {
|
||||
|
|
|
@ -8,14 +8,20 @@ import java.util.Set;
|
|||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
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.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.StructureDefinitionSnapshotComponent;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
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.AllArgsConstructor;
|
||||
|
@ -267,12 +273,28 @@ public class ProfilePathProcessor {
|
|||
|
||||
if (!diffMatches.get(0).hasSlicing())
|
||||
outcome.setSlicing(profileUtilities.makeExtensionSlicing());
|
||||
else
|
||||
else {
|
||||
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 (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
}
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
slicerElement = outcome;
|
||||
|
||||
|
@ -337,6 +359,20 @@ public class ProfilePathProcessor {
|
|||
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) {
|
||||
int start = 0;
|
||||
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
|
||||
|
@ -344,13 +380,14 @@ public class ProfilePathProcessor {
|
|||
ElementDefinition elementToRemove = 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.
|
||||
String path = diffMatches.get(0).getPath();
|
||||
if (shortCut) {
|
||||
// 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...
|
||||
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
|
||||
ElementDefinition ed = new ElementDefinition();
|
||||
ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath));
|
||||
ed.setPath(profileUtilities.determineTypeSlicePath(path, currentBasePath));
|
||||
for (TypeSlice ts : typeList)
|
||||
ed.addType().setCode(ts.getType());
|
||||
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.
|
||||
// see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element
|
||||
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.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this");
|
||||
ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED);
|
||||
|
@ -374,6 +411,13 @@ public class ProfilePathProcessor {
|
|||
getDifferential().getElement().add(newDiffCursor, 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);
|
||||
// the first element is setting up the slicing
|
||||
|
@ -429,7 +473,7 @@ public class ProfilePathProcessor {
|
|||
.processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor,
|
||||
cursors.contextName, cursors.resultPathBase));
|
||||
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.
|
||||
elementDefinition.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent());
|
||||
elementDefinition.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this");
|
||||
|
@ -607,6 +651,7 @@ public class ProfilePathProcessor {
|
|||
cursors.resultPathBase = outcome.getPath();
|
||||
else if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
cursors.baseCursor++;
|
||||
cursors.diffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)) + 1;
|
||||
|
@ -731,6 +776,7 @@ public class ProfilePathProcessor {
|
|||
cursors.resultPathBase = outcome.getPath();
|
||||
else if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), cursors.resultPathBase));
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) {
|
||||
// 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;
|
||||
while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + "."))
|
||||
cursors.diffCursor++;
|
||||
|
@ -807,7 +856,7 @@ public class ProfilePathProcessor {
|
|||
}
|
||||
cursors.contextName = dt.getUrl();
|
||||
if (getRedirector() == null || getRedirector().isEmpty()) {
|
||||
|
||||
|
||||
this
|
||||
.incrementDebugIndent()
|
||||
.withBaseLimit(dt.getSnapshot().getElement().size() - 1)
|
||||
|
@ -893,6 +942,7 @@ public class ProfilePathProcessor {
|
|||
diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called
|
||||
}
|
||||
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
|
||||
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);
|
||||
for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -978,6 +1030,7 @@ public class ProfilePathProcessor {
|
|||
cursors.diffCursor = newDiffLimit + 1;
|
||||
diffpos++;
|
||||
} else {
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
cursors.baseCursor++;
|
||||
// just copy any children on the base
|
||||
|
@ -988,6 +1041,7 @@ public class ProfilePathProcessor {
|
|||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
outcome.setUserData(profileUtilities.UD_BASE_PATH, outcome.getPath());
|
||||
outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl());
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
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
|
||||
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived());
|
||||
profileUtilities.removeStatusExtensions(outcome);
|
||||
|
@ -1079,6 +1134,12 @@ public class ProfilePathProcessor {
|
|||
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) {
|
||||
int start = 0;
|
||||
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
|
||||
|
@ -1252,6 +1313,7 @@ public class ProfilePathProcessor {
|
|||
cursors.resultPathBase = outcome.getPath();
|
||||
else if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
// the profile walks into this, so we need to as well
|
||||
// did we implicitly step into a new type?
|
||||
|
@ -1295,6 +1357,7 @@ public class ProfilePathProcessor {
|
|||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
if (!outcome.getPath().startsWith(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
|
||||
outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl());
|
||||
outcome.setUserData(profileUtilities.UD_BASE_PATH, cursors.resultPathBase);
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.conformance.ElementRedirection;
|
||||
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.elementmodel.ObjectConverter;
|
||||
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.Coding;
|
||||
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.DiscriminatorType;
|
||||
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 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 {
|
||||
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
|
||||
|
@ -288,6 +317,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
private Map<ElementDefinition, SourcedChildDefinitions> childMapCache = new HashMap<>();
|
||||
private AllowUnknownProfile allowUnknownProfile = AllowUnknownProfile.ALL_TYPES;
|
||||
private MappingMergeModeOption mappingMergeMode = MappingMergeModeOption.APPEND;
|
||||
private boolean forPublication;
|
||||
|
||||
public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) {
|
||||
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
|
||||
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
|
||||
for (TypeRefComponent t : ed.getType()) {
|
||||
|
@ -3978,5 +4051,16 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
return defn.getIsModifier();
|
||||
}
|
||||
|
||||
|
||||
public boolean isForPublication() {
|
||||
return forPublication;
|
||||
}
|
||||
|
||||
public void setForPublication(boolean forPublication) {
|
||||
this.forPublication = forPublication;
|
||||
}
|
||||
|
||||
public List<ValidationMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -943,6 +943,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (!t.hasResult()) {
|
||||
try {
|
||||
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs);
|
||||
vsc.setThrowToServer(options.isUseServer() && tcc.getClient() != null);
|
||||
ValidationResult res = vsc.validateCode("Coding", t.getCoding());
|
||||
if (txCache != null) {
|
||||
txCache.cacheValidation(t.getCacheToken(), res, TerminologyCache.TRANSIENT);
|
||||
|
@ -1059,12 +1060,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
|
||||
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
Set<String> unknownSystems = new HashSet<>();
|
||||
|
||||
String localError = null;
|
||||
if (options.isUseClient()) {
|
||||
// ok, first we try to validate locally
|
||||
try {
|
||||
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs, ctxt);
|
||||
vsc.setUnknownSystems(unknownSystems);
|
||||
vsc.setThrowToServer(options.isUseServer() && tcc.getClient() != null);
|
||||
if (!ValueSetUtilities.isServerSide(code.getSystem())) {
|
||||
res = vsc.validateCode(path, code);
|
||||
if (txCache != null) {
|
||||
|
@ -1084,7 +1088,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
|
||||
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()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
Set<String> unknownSystems = new HashSet<>();
|
||||
|
||||
if (options.isUseClient()) {
|
||||
// ok, first we try to validate locally
|
||||
try {
|
||||
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs);
|
||||
vsc.setUnknownSystems(unknownSystems);
|
||||
vsc.setThrowToServer(options.isUseServer() && tcc.getClient() != null);
|
||||
res = vsc.validateCode("CodeableConcept", code);
|
||||
txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT);
|
||||
return res;
|
||||
|
@ -1349,6 +1360,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
version = ((PrimitiveType<?>) p.getValue()).asStringValue();
|
||||
} else if (p.getName().equals("code")) {
|
||||
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")) {
|
||||
try {
|
||||
IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue());
|
||||
|
|
|
@ -123,6 +123,7 @@ public interface IWorkerContext {
|
|||
private String diagnostics;
|
||||
private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
private CodeableConcept codeableConcept;
|
||||
private Set<String> unknownSystems;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -239,7 +240,12 @@ public interface IWorkerContext {
|
|||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ValidationResult addToMessage(String message) {
|
||||
this.message = this.message == null ? message : this.message +"; "+ message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ValidationResult setErrorClass(TerminologyServiceErrorClass errorClass) {
|
||||
this.errorClass = errorClass;
|
||||
return this;
|
||||
|
@ -288,7 +294,16 @@ public interface IWorkerContext {
|
|||
public CodeableConcept getCodeableConcept() {
|
||||
return codeableConcept;
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getUnknownSystems() {
|
||||
return unknownSystems;
|
||||
}
|
||||
|
||||
public ValidationResult setUnknownSystems(Set<String> unknownSystems) {
|
||||
this.unknownSystems = unknownSystems;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CodingValidationRequest {
|
||||
|
|
|
@ -113,6 +113,9 @@ public class Manager {
|
|||
}
|
||||
|
||||
public static ParserBase makeParser(IWorkerContext context, FhirFormat format) {
|
||||
if (format == null) {
|
||||
throw new Error("Programming logic error: no format known");
|
||||
}
|
||||
switch (format) {
|
||||
case JSON : return new JsonParser(context);
|
||||
case XML : return new XmlParser(context);
|
||||
|
|
|
@ -1413,12 +1413,17 @@ public class ElementDefinition extends BackboneType implements ICompositeType {
|
|||
, ordered, rules);
|
||||
}
|
||||
|
||||
public String fhirType() {
|
||||
return "ElementDefinition.slicing";
|
||||
public String fhirType() {
|
||||
return "ElementDefinition.slicing";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return (ordered == null ? "??" : "true".equals(ordered.asStringValue()) ? "ordered" : "unordered")+"/"+
|
||||
(rules == null ? "??" : rules.asStringValue())+" "+discriminator.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Block()
|
||||
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()
|
||||
|
|
|
@ -167,7 +167,7 @@ public class ElementWrappers {
|
|||
Property family = b.getChildByName("family");
|
||||
Property given = wrapped.getChildByName("given");
|
||||
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();
|
||||
return s;
|
||||
} else {
|
||||
|
|
|
@ -11,6 +11,13 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
|||
public class ValidationProcessInfo {
|
||||
private TerminologyServiceErrorClass err;
|
||||
private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
|
||||
public ValidationProcessInfo() {
|
||||
}
|
||||
|
||||
public ValidationProcessInfo(List<OperationOutcomeIssueComponent> issues) {
|
||||
this.issues = issues;
|
||||
}
|
||||
public TerminologyServiceErrorClass getErr() {
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ public class ValueSetValidator {
|
|||
private List<CodeSystem> localSystems = new ArrayList<>();
|
||||
Parameters expansionProfile;
|
||||
private TerminologyCapabilities txCaps;
|
||||
private Set<String> unknownSystems;
|
||||
private boolean throwToServer;
|
||||
|
||||
public ValueSetValidator(ValidationOptions options, ValueSet source, IWorkerContext context, Parameters expansionProfile, TerminologyCapabilities txCaps) {
|
||||
this.valueset = source;
|
||||
|
@ -120,6 +122,22 @@ public class ValueSetValidator {
|
|||
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() {
|
||||
if (localContext != null) {
|
||||
if (valueset != null) {
|
||||
|
@ -174,10 +192,16 @@ public class ValueSetValidator {
|
|||
if (context.isNoTerminologyServer()) {
|
||||
if (c.hasVersion()) {
|
||||
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 {
|
||||
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 {
|
||||
res = context.validateCode(options.withNoClient(), c, null);
|
||||
|
@ -191,8 +215,9 @@ public class ValueSetValidator {
|
|||
}
|
||||
}
|
||||
Coding foundCoding = null;
|
||||
String msg = null;
|
||||
Boolean result = false;
|
||||
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
|
||||
Boolean result = false;
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(", ");
|
||||
|
||||
for (Coding c : code.getCoding()) {
|
||||
|
@ -212,11 +237,11 @@ public class ValueSetValidator {
|
|||
}
|
||||
}
|
||||
if (result == null) {
|
||||
String msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl(), b.toString());
|
||||
info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path, msg));
|
||||
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, unknownSystems.isEmpty() ? IssueType.INVALID : IssueType.NOTFOUND, path, msg));
|
||||
} 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());
|
||||
info.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
|
||||
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, unknownSystems.isEmpty() ? IssueType.INVALID : IssueType.NOTFOUND, path, msg));
|
||||
}
|
||||
}
|
||||
if (info.hasErrors()) {
|
||||
|
@ -229,8 +254,11 @@ public class ValueSetValidator {
|
|||
res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : ((CodeSystem) foundCoding.getUserData("cs")).getVersion());
|
||||
res.setDisplay(cd.getDisplay());
|
||||
}
|
||||
res.setUnknownSystems(unknownSystems);
|
||||
res.addCodeableConcept(vcc);
|
||||
return res;
|
||||
} else if (result == null) {
|
||||
return new ValidationResult(IssueSeverity.WARNING, info.summary(), info.getIssues());
|
||||
} 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"));
|
||||
} 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) {
|
||||
if (c.hasVersion()) {
|
||||
return c.getVersion();
|
||||
|
@ -329,6 +366,7 @@ public class ValueSetValidator {
|
|||
ValidationResult res = null;
|
||||
boolean inExpansion = false;
|
||||
boolean inInclude = false;
|
||||
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
VersionInfo vi = new VersionInfo(this);
|
||||
|
||||
String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull();
|
||||
|
@ -363,8 +401,10 @@ public class ValueSetValidator {
|
|||
if (cs == null) {
|
||||
if (wv == null) {
|
||||
warningMessage = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, system);
|
||||
unknownSystems.add(system);
|
||||
} else {
|
||||
warningMessage = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, system, wv, resolveCodeSystemVersions(system).toString());
|
||||
unknownSystems.add(system+"|"+wv);
|
||||
}
|
||||
if (!inExpansion) {
|
||||
if (valueset != null && valueset.hasExpansion()) {
|
||||
|
@ -372,18 +412,18 @@ public class ValueSetValidator {
|
|||
valueset.getUrl(),
|
||||
code.getSystem(),
|
||||
code.getCode().toString());
|
||||
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path, msg));
|
||||
throw new VSCheckerException(msg, issues);
|
||||
} else {
|
||||
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
issues.addAll(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".system", warningMessage));
|
||||
res = new ValidationResult(IssueSeverity.WARNING, warningMessage, issues);
|
||||
if (valueset == null) {
|
||||
throw new VSCheckerException(warningMessage, issues);
|
||||
} else {
|
||||
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));
|
||||
throw new VSCheckerException(warningMessage+"; "+msg, issues);
|
||||
// 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));
|
||||
// we don't do this yet
|
||||
// throw new VSCheckerException(warningMessage, issues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +447,7 @@ public class ValueSetValidator {
|
|||
// we'll take it on faith
|
||||
String disp = getPreferredDisplay(cc);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -419,12 +459,14 @@ public class ValueSetValidator {
|
|||
// 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());
|
||||
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 {
|
||||
// well, we didn't find a code system - try the expansion?
|
||||
// disabled waiting for discussion
|
||||
throw new FHIRException("No try the server");
|
||||
if (throwToServer) {
|
||||
throw new FHIRException("No; try the server");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inExpansion = checkExpansion(code, vi);
|
||||
|
@ -432,7 +474,7 @@ public class ValueSetValidator {
|
|||
}
|
||||
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
|
||||
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
|
||||
|
@ -446,20 +488,24 @@ public class ValueSetValidator {
|
|||
res.setErrorClass(info.getErr());
|
||||
}
|
||||
if (ok == null) {
|
||||
res.setMessage("Unable to check whether code is in value set "+valueset.getUrl()+": "+info.summary()).setSeverity(IssueSeverity.WARNING);
|
||||
res.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.EXCEPTION, path, res.getMessage()));
|
||||
String m = "Unable to check whether the code is in the value set "+valueset.getVersionedUrl();
|
||||
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) {
|
||||
if (!info.getIssues().isEmpty()) {
|
||||
res.setMessage("Not in value set "+valueset.getUrl()+": "+info.summary()).setSeverity(IssueSeverity.ERROR);
|
||||
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, res.getMessage()));
|
||||
} 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);
|
||||
// if (!info.getIssues().isEmpty()) {
|
||||
// res.setMessage("Not in value set "+valueset.getUrl()+": "+info.summary()).setSeverity(IssueSeverity.ERROR);
|
||||
// res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, res.getMessage()));
|
||||
// } else
|
||||
// {
|
||||
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.setDefinition(null);
|
||||
res.setSystem(null);
|
||||
res.setDisplay(null);
|
||||
}
|
||||
// }
|
||||
} else if (warningMessage!=null) {
|
||||
String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage);
|
||||
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())) {
|
||||
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.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
|
||||
}
|
||||
|
@ -483,7 +529,7 @@ public class ValueSetValidator {
|
|||
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/",
|
||||
"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 {
|
||||
return codeInValueSet("code", system, version, code, info);
|
||||
}
|
||||
|
||||
public Boolean codeInValueSet(String path, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
if (valueset == null) {
|
||||
return false;
|
||||
|
@ -991,30 +1038,42 @@ public class ValueSetValidator {
|
|||
// ok, we need the code system
|
||||
CodeSystem cs = resolveCodeSystem(system, version);
|
||||
if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) {
|
||||
// make up a transient value set with
|
||||
ValueSet vs = new ValueSet();
|
||||
vs.setStatus(PublicationStatus.ACTIVE);
|
||||
vs.setUrl(valueset.getUrl()+"--"+vsiIndex);
|
||||
vs.setVersion(valueset.getVersion());
|
||||
vs.getCompose().addInclude(vsi);
|
||||
ValidationResult res = context.validateCode(options.withNoClient(), new Coding(system, code, null), vs);
|
||||
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
|
||||
if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
|
||||
// server didn't know the code system either - we'll take it face value
|
||||
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system)));
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
if (cc.getCode().equals(code)) {
|
||||
return true;
|
||||
if (throwToServer) {
|
||||
// make up a transient value set with
|
||||
ValueSet vs = new ValueSet();
|
||||
vs.setStatus(PublicationStatus.ACTIVE);
|
||||
vs.setUrl(valueset.getUrl()+"--"+vsiIndex);
|
||||
vs.setVersion(valueset.getVersion());
|
||||
vs.getCompose().addInclude(vsi);
|
||||
ValidationResult res = context.validateCode(options.withNoClient(), new Coding(system, code, null), vs);
|
||||
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
|
||||
if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
|
||||
// server didn't know the code system either - we'll take it face value
|
||||
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system)));
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
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 {
|
||||
if (vsi.hasFilter()) {
|
||||
ok = true;
|
||||
|
|
|
@ -100,7 +100,7 @@ public interface IResourceValidator {
|
|||
void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars);
|
||||
|
||||
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
|
||||
|
|
|
@ -585,8 +585,8 @@ public class SnapShotGenerationTests {
|
|||
|
||||
boolean structureDefinitionEquality = t1.equalsDeep(t2);
|
||||
if (!structureDefinitionEquality) {
|
||||
System.out.println("Encountered unexpected diff in structure definition");
|
||||
DiffUtils.testDiff(dst.getAbsolutePath(), actualFilePath);
|
||||
System.out.println("Encountered unexpected change in diff in structure definition");
|
||||
// DiffUtils.testDiff(dst.getAbsolutePath(), actualFilePath);
|
||||
}
|
||||
Assertions.assertTrue(structureDefinitionEquality, "Output does not match expected");
|
||||
}
|
||||
|
|
|
@ -590,7 +590,7 @@ public class Utilities {
|
|||
public static boolean isPlural(String word) {
|
||||
word = word.toLowerCase();
|
||||
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;
|
||||
Inflector inf = new Inflector();
|
||||
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());
|
||||
}
|
||||
|
||||
public static String[] splitLines(String txt) {
|
||||
return txt.split("\\r?\\n|\\r");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 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 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";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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_U = {0}. {1}
|
||||
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_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}
|
||||
|
@ -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_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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
private ValidationLevel level = ValidationLevel.HINTS;
|
||||
protected Coding jurisdiction;
|
||||
protected boolean allowExamples;
|
||||
protected boolean forPublication;
|
||||
|
||||
public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager) {
|
||||
super();
|
||||
|
@ -1242,7 +1243,16 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -505,7 +505,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private ValidationOptions baseOptions = new ValidationOptions();
|
||||
private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>();
|
||||
private boolean logProgress;
|
||||
private boolean forPublication;
|
||||
|
||||
public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices, XVerExtensionManager xverManager) {
|
||||
super(theContext, xverManager);
|
||||
|
@ -2394,18 +2393,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
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());
|
||||
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])(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;
|
||||
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;
|
||||
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;
|
||||
try {
|
||||
DateTimeType dt = new DateTimeType(e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_VALID, ex.getMessage());
|
||||
ok = false;
|
||||
boolean dok = 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])(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;
|
||||
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;
|
||||
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;
|
||||
if (dok) {
|
||||
try {
|
||||
DateTimeType dt = new DateTimeType(e.primitiveValue());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
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")) {
|
||||
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")) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
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;
|
||||
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;
|
||||
try {
|
||||
DateType dt = new DateType(e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATE_VALID, ex.getMessage());
|
||||
ok = false;
|
||||
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");
|
||||
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;
|
||||
if (dok) {
|
||||
try {
|
||||
DateType dt = new DateType(e.primitiveValue());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
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")) {
|
||||
String encoded = e.primitiveValue();
|
||||
|
@ -2511,15 +2516,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
if (type.equals("instant")) {
|
||||
ok = 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;
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
try {
|
||||
InstantType dt = new InstantType(e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INSTANT_VALID, ex.getMessage());
|
||||
ok = false;
|
||||
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()+"' doesn't meet format requirements for instant)");
|
||||
if (dok) {
|
||||
try {
|
||||
InstantType dt = new InstantType(e.primitiveValue());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, yearIsValid(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_REASONABLE, e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
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) {
|
||||
|
@ -5040,7 +5048,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else if (element.getType().equals("SearchParameter")) {
|
||||
return new SearchParameterValidator(context, timeTracker, fpe, xverManager, jurisdiction).validateSearchParameter(errors, element, stack);
|
||||
} 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")) {
|
||||
return new StructureMapValidator(context, timeTracker, fpe, xverManager,profileUtilities, jurisdiction).validateStructureMap(errors, element, stack);
|
||||
} else if (element.getType().equals("ValueSet")) {
|
||||
|
@ -6527,14 +6535,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
this.logProgress = logProgress;
|
||||
}
|
||||
|
||||
public boolean isForPublication() {
|
||||
return forPublication;
|
||||
}
|
||||
|
||||
public void setForPublication(boolean forPublication) {
|
||||
this.forPublication = forPublication;
|
||||
}
|
||||
|
||||
public boolean isDisplayWarnings() {
|
||||
return baseOptions.isDisplayWarningMode();
|
||||
}
|
||||
|
@ -6543,4 +6543,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
baseOptions.setDisplayWarningMode(displayWarnings);
|
||||
}
|
||||
|
||||
|
||||
public InstanceValidator setForPublication(boolean forPublication) {
|
||||
this.forPublication = forPublication;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -60,13 +60,14 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
private FHIRPathEngine fpe;
|
||||
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);
|
||||
source = Source.InstanceValidator;
|
||||
this.fpe = fpe;
|
||||
this.timeTracker = timeTracker;
|
||||
this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged;
|
||||
this.jurisdiction = jurisdiction;
|
||||
this.forPublication = forPublication;
|
||||
}
|
||||
|
||||
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());
|
||||
List<ValidationMessage> msgs = new ArrayList<>();
|
||||
ProfileUtilities pu = new ProfileUtilities(context, msgs, null);
|
||||
pu.setForPublication(forPublication);
|
||||
pu.setXver(xverManager);
|
||||
pu.setNewSlicingProcessing(!sd.hasFhirVersion() || VersionUtilities.isR4Plus(sd.getFhirVersion().toCode()));
|
||||
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;
|
||||
}
|
||||
}
|
||||
} catch (FHIRException | IOException e) {
|
||||
} catch (Exception e) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
|
||||
ok = false;
|
||||
}
|
||||
|
|
|
@ -175,19 +175,19 @@ public class SnapShotGenerationXTests {
|
|||
}
|
||||
|
||||
public void load(String version) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
if (UtilitiesXTests.findTestResource("rX", "snapshot-generation", id + "-input.json"))
|
||||
source = (StructureDefinition) XVersionLoader.loadJson(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", id + "-input.json"));
|
||||
if (TestingUtilities.findTestResource("rX", "snapshot-generation", id + "-input.json"))
|
||||
source = (StructureDefinition) XVersionLoader.loadJson(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", id + "-input.json"));
|
||||
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)
|
||||
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))
|
||||
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 (UtilitiesXTests.findTestResource("rX", "snapshot-generation", register + ".xml")) {
|
||||
included = (StructureDefinition) XVersionLoader.loadXml(version, UtilitiesXTests.loadTestResourceStream("rX", "snapshot-generation", register + ".xml"));
|
||||
if (TestingUtilities.findTestResource("rX", "snapshot-generation", register + ".xml")) {
|
||||
included = (StructureDefinition) XVersionLoader.loadXml(version, TestingUtilities.loadTestResourceStream("rX", "snapshot-generation", register + ".xml"));
|
||||
} 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 {
|
||||
|
||||
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());
|
||||
List<Object[]> objects = new ArrayList<Object[]>();
|
||||
while (test != null && test.getNodeName().equals("test")) {
|
||||
|
@ -471,7 +471,7 @@ public class SnapShotGenerationXTests {
|
|||
pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors, false);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
IOUtils.copy(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());
|
||||
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"));
|
||||
if (dst.exists())
|
||||
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);
|
||||
StructureDefinition t1 = test.expected.copy();
|
||||
t1.setText(null);
|
||||
|
|
|
@ -280,6 +280,11 @@ public class TerminologyServiceTests {
|
|||
if (vm.getCodeableConcept() != null) {
|
||||
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) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.getIssue().addAll(vm.getIssues());
|
||||
|
|
|
@ -202,6 +202,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
byte[] testCaseContent = TestingUtilities.loadTestResource("validator", JsonUtilities.str(content, "file")).getBytes(StandardCharsets.UTF_8);
|
||||
// load and process content
|
||||
FhirFormat fmt = determineFormat(content, testCaseContent);
|
||||
if (fmt == null) {
|
||||
throw new FHIRException("Unknown format in source "+JsonUtilities.str(content, "file"));
|
||||
}
|
||||
|
||||
InstanceValidator val = vCurr.getValidator(fmt);
|
||||
val.setWantCheckSnapshotUnchanged(true);
|
||||
|
@ -238,6 +241,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
val.setValidationLanguage(content.get("language").getAsString());
|
||||
else
|
||||
val.setValidationLanguage(null);
|
||||
val.setForPublication(content.has("for-publication") && "true".equals(content.get("for-publication").getAsString()));
|
||||
if (content.has("default-version")) {
|
||||
val.setBaseOptions(val.getBaseOptions().withVersionFlexible(content.get("default-version").getAsBoolean()));
|
||||
} else {
|
||||
|
|
|
@ -1116,3 +1116,39 @@ v: {
|
|||
"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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -63,3 +63,35 @@ v: {
|
|||
"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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -3167,3 +3167,279 @@ v: {
|
|||
"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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -2116,3 +2116,37 @@ v: {
|
|||
"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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
|
@ -752,3 +752,73 @@ v: {
|
|||
"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"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -19,7 +19,7 @@
|
|||
|
||||
<properties>
|
||||
<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>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
|
Loading…
Reference in New Issue