mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-02-07 21:38:15 +00:00
Add matchetype pattern validation
This commit is contained in:
parent
c0bcdc6293
commit
ac4f050bac
@ -1189,4 +1189,9 @@ public class I18nConstants {
|
||||
public static final String VALIDATION_AI_FAILED = "VALIDATION_AI_FAILED";
|
||||
public static final String VALIDATION_AI_FAILED_LOG = "VALIDATION_AI_FAILED_LOG";
|
||||
public static final String RESOURCE_DUPLICATE_CONTAINED_ID = "RESOURCE_DUPLICATE_CONTAINED_ID";
|
||||
public static final String RESOURCE_MATCHETYPE_REQUIRED = "RESOURCE_MATCHETYPE_REQUIRED";
|
||||
public static final String RESOURCE_MATCHETYPE_DISALLOWED = "RESOURCE_MATCHETYPE_DISALLOWED";
|
||||
public static final String RESOURCE_NOT_MATCHETYPE_EXTENSION = "RESOURCE_NOT_MATCHETYPE_EXTENSION";
|
||||
public static final String RESOURCE_MATCHETYPE_SUSPECT_TYPE = "RESOURCE_MATCHETYPE_SUSPECT_TYPE";
|
||||
public static final String RESOURCE_MATCHETYPE_UNKNOWN_PATTERN = "RESOURCE_MATCHETYPE_UNKNOWN_PATTERN";
|
||||
}
|
||||
|
@ -1220,4 +1220,8 @@ VALIDATION_AI_TEXT_CODE = Apparent mis-match between code ''{0}'' and text ''{1}
|
||||
VALIDATION_AI_FAILED = Consulting AI failed: {0}
|
||||
VALIDATION_AI_FAILED_LOG = Consulting AI failed: {0} (see {1} for further details)
|
||||
RESOURCE_DUPLICATE_CONTAINED_ID = Duplicate ID for contained resource: {0}
|
||||
|
||||
RESOURCE_MATCHETYPE_REQUIRED = This resource is required to be a matchetype resource (extension http://hl7.org/fhir/tools/StructureDefinition/matchetype must be true)
|
||||
RESOURCE_MATCHETYPE_DISALLOWED = This resource is not allowed to be a matchetype resource (extension http://hl7.org/fhir/tools/StructureDefinition/matchetype is true)
|
||||
RESOURCE_NOT_MATCHETYPE_EXTENSION = This resource is not a matcehtype, so it cannot have the extension {0}
|
||||
RESOURCE_MATCHETYPE_SUSPECT_TYPE = The type ''{0}'' does not appear to match the matchetype pattern value ''{1}''
|
||||
RESOURCE_MATCHETYPE_UNKNOWN_PATTERN = The matchetype pattern value ''{1}'' is not valid
|
||||
|
@ -197,6 +197,7 @@ import org.hl7.fhir.validation.ai.CodeAndTextValidator;
|
||||
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
|
||||
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
|
||||
import org.hl7.fhir.validation.codesystem.CodingsObserver;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator.MatchetypeStatus;
|
||||
import org.hl7.fhir.validation.instance.type.BundleValidator;
|
||||
import org.hl7.fhir.validation.instance.type.CodeSystemValidator;
|
||||
import org.hl7.fhir.validation.instance.type.ConceptMapValidator;
|
||||
@ -245,6 +246,10 @@ import org.w3c.dom.Document;
|
||||
|
||||
public class InstanceValidator extends BaseValidator implements IResourceValidator {
|
||||
|
||||
public enum MatchetypeStatus {
|
||||
Disallowed, Allowed, Required
|
||||
}
|
||||
|
||||
public enum BindingContext {
|
||||
BASE, MAXVS, ADDITIONAL
|
||||
|
||||
@ -627,6 +632,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
private String aiService;
|
||||
private Set<Integer> textsToCheckKeys = new HashSet<>();
|
||||
private String cacheFolder;
|
||||
private MatchetypeStatus matchetypeStatus = MatchetypeStatus.Disallowed;
|
||||
|
||||
public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager, ValidatorSession session) {
|
||||
super(theContext, xverManager, false, session);
|
||||
@ -2447,6 +2453,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
String u = url.contains("|") ? url.substring(0, url.indexOf("|")) : url;
|
||||
boolean isModifier = element.getName().equals("modifierExtension");
|
||||
assert def.getIsModifier() == isModifier;
|
||||
|
||||
ok = rule(errors, "2025-01-28", IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']",
|
||||
valContext.isMatchetype() || !Utilities.existsInList(url, "http://hl7.org/fhir/tools/StructureDefinition/matchetype-optional",
|
||||
"http://hl7.org/fhir/tools/StructureDefinition/matchetype-count", "http://hl7.org/fhir/tools/StructureDefinition/matchetype-value"),
|
||||
I18nConstants.RESOURCE_NOT_MATCHETYPE_EXTENSION, url) && ok;
|
||||
|
||||
long t = System.nanoTime();
|
||||
StructureDefinition ex = Utilities.isAbsoluteUrl(u) ? context.fetchResource(StructureDefinition.class, u) : null;
|
||||
@ -3072,336 +3083,380 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
}
|
||||
warningPlural(errors, "2023-07-26", IssueType.INVALID, e.line(), e.col(), path, badChars.isEmpty(), badChars.size(), I18nConstants.UNICODE_XML_BAD_CHARS, badChars.toString());
|
||||
}
|
||||
if (context.hasExtension(ToolingExtensions.EXT_MIN_LENGTH) && e.hasPrimitiveValue()) {
|
||||
int length = e.primitiveValue().length();
|
||||
int spec = ToolingExtensions.readIntegerExtension(context, ToolingExtensions.EXT_MIN_LENGTH, 0);
|
||||
ok = rule(errors, "2024-11-02", IssueType.INVALID, e.line(), e.col(), path, length >= spec, I18nConstants.PRIMITIVE_TOO_SHORT, length, spec) && ok;
|
||||
|
||||
}
|
||||
String regex = context.getExtensionString(ToolingExtensions.EXT_REGEX);
|
||||
// there's a messy history here - this extension snhould only be on the element definition itself, but for historical reasons
|
||||
//( see task 13328) it might also be found on one the types
|
||||
if (regex != null) {
|
||||
for (TypeRefComponent tr : context.getType()) {
|
||||
if (tr.hasExtension(ToolingExtensions.EXT_REGEX)) {
|
||||
regex = tr.getExtensionString(ToolingExtensions.EXT_REGEX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (regex != null) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue().matches(regex), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX, e.primitiveValue(), regex) && ok;
|
||||
}
|
||||
|
||||
if (!"xhtml".equals(type)) {
|
||||
if (securityChecks) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !containsHtmlTags(e.primitiveValue()), I18nConstants.SECURITY_STRING_CONTENT_ERROR) && ok;
|
||||
} else if (!"markdown".equals(type)){
|
||||
hint(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !containsHtmlTags(e.primitiveValue()), I18nConstants.SECURITY_STRING_CONTENT_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (type.equals("boolean")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, "true".equals(e.primitiveValue()) || "false".equals(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BOOLEAN_VALUE) && ok;
|
||||
}
|
||||
if (type.equals("uri") || type.equals("oid") || type.equals("uuid") || type.equals("url") || type.equals("canonical")) {
|
||||
String url = e.primitiveValue();
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !url.startsWith("oid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URI_OID) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !url.startsWith("uuid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URI_UUID) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.equals(Utilities.trimWS(url).replace(" ", ""))
|
||||
// work around an old invalid example in a core package
|
||||
|| "http://www.acme.com/identifiers/patient or urn:ietf:rfc:3986 if the Identifier.value itself is a full uri".equals(url), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URI_WS, url) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || url.length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && 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;
|
||||
if (valContext.isMatchetype() && e.primitiveValue().startsWith("$")) {
|
||||
switch (e.primitiveValue()) {
|
||||
case "$semver$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "code"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$url$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "url", "uri", "uuid", "oid", "canonical"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$token$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "code"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$string$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "string"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$date$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "date", "dateTime"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$version$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "code"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$id$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "id"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$instant$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "dateTime", "instant"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$uuid$":
|
||||
warning(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, Utilities.existsInList(type, "url", "uri", "uuid", "canonical"), I18nConstants.RESOURCE_MATCHETYPE_SUSPECT_TYPE, type, e.primitiveValue());
|
||||
break;
|
||||
case "$$":
|
||||
break;
|
||||
default:
|
||||
if (e.primitiveValue().startsWith("$external:")) {
|
||||
|
||||
if (type.equals("oid")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.startsWith("urn:oid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_OID_START) && ok;
|
||||
}
|
||||
if (type.equals("uuid")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.startsWith("urn:uuid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_UUID_STRAT) && ok;
|
||||
}
|
||||
if (type.equals("canonical")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.startsWith("#") || Utilities.isAbsoluteUrl(url), I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE, url) && ok;
|
||||
}
|
||||
} else if (e.primitiveValue().startsWith("$choice:")) {
|
||||
|
||||
if (url != null && url.startsWith("urn:uuid:")) {
|
||||
String s = url.substring(9);
|
||||
if (s.contains("#")) {
|
||||
s = s.substring(0, s.indexOf("#"));
|
||||
} else if (e.primitiveValue().startsWith("$fragments:")) {
|
||||
|
||||
} else {
|
||||
rule(errors, "2025-01-28", IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.RESOURCE_MATCHETYPE_UNKNOWN_PATTERN, e.primitiveValue());
|
||||
}
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isValidUUID(s), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_UUID_VALID, s) && ok;
|
||||
}
|
||||
if (url != null && url.startsWith("urn:oid:")) {
|
||||
String cc = url.substring(8);
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
|
||||
// OIDs roots shorter than 4 chars are almost never valid for namespaces except for 1.3.x
|
||||
Utilities.isOid(cc) && ((cc.lastIndexOf('.') >= 4 || cc.startsWith("1.3"))),
|
||||
I18nConstants.TYPE_SPECIFIC_CHECKS_DT_OID_VALID, cc) && ok;
|
||||
} else {
|
||||
if (context.hasExtension(ToolingExtensions.EXT_MIN_LENGTH) && e.hasPrimitiveValue()) {
|
||||
int length = e.primitiveValue().length();
|
||||
int spec = ToolingExtensions.readIntegerExtension(context, ToolingExtensions.EXT_MIN_LENGTH, 0);
|
||||
ok = rule(errors, "2024-11-02", IssueType.INVALID, e.line(), e.col(), path, length >= spec, I18nConstants.PRIMITIVE_TOO_SHORT, length, spec) && ok;
|
||||
|
||||
}
|
||||
String regex = context.getExtensionString(ToolingExtensions.EXT_REGEX);
|
||||
// there's a messy history here - this extension snhould only be on the element definition itself, but for historical reasons
|
||||
//( see task 13328) it might also be found on one the types
|
||||
if (regex != null) {
|
||||
for (TypeRefComponent tr : context.getType()) {
|
||||
if (tr.hasExtension(ToolingExtensions.EXT_REGEX)) {
|
||||
regex = tr.getExtensionString(ToolingExtensions.EXT_REGEX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (regex != null) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue().matches(regex), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX, e.primitiveValue(), regex) && ok;
|
||||
}
|
||||
|
||||
if (isCanonicalURLElement(e, node)) {
|
||||
// we get to here if this is a defining canonical URL (e.g. CodeSystem.url)
|
||||
// the URL must be an IRI if present
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isAbsoluteUrl(url),
|
||||
node.isContained() ? I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_CONTAINED : I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE, url) && ok;
|
||||
} else if (!e.getProperty().getDefinition().getPath().equals("Bundle.entry.fullUrl")) { // we don't check fullUrl here; it's not a reference, it's a definition. It'll get checked as part of checking the bundle
|
||||
ok = validateReference(valContext, errors, path, type, context, e, url) && ok;
|
||||
}
|
||||
}
|
||||
if (type.equals(ID) && !"Resource.id".equals(context.getBase().getPath())) {
|
||||
// work around an old issue with ElementDefinition.id
|
||||
if (!context.getPath().equals("ElementDefinition.id")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, FormatUtilities.isValidId(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ID_VALID, e.primitiveValue()) && ok;
|
||||
}
|
||||
}
|
||||
if (type.equalsIgnoreCase("string") && e.hasPrimitiveValue()) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue() == null || e.primitiveValue().length() > 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_NOTEMPTY)) {
|
||||
if (warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue() == null || !Utilities.isAllWhitespace(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_STRING_WS_ALL, prepWSPresentation(e.primitiveValue()))) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue() == null || Utilities.trimWS(e.primitiveValue()).equals(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_STRING_WS, prepWSPresentation(e.primitiveValue()));
|
||||
if (!"xhtml".equals(type)) {
|
||||
if (securityChecks) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !containsHtmlTags(e.primitiveValue()), I18nConstants.SECURITY_STRING_CONTENT_ERROR) && ok;
|
||||
} else if (!"markdown".equals(type)){
|
||||
hint(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !containsHtmlTags(e.primitiveValue()), I18nConstants.SECURITY_STRING_CONTENT_WARNING);
|
||||
}
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue().length() <= 1048576, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_STRING_LENGTH)) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && ok;
|
||||
}
|
||||
|
||||
|
||||
if (type.equals("boolean")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, "true".equals(e.primitiveValue()) || "false".equals(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BOOLEAN_VALUE) && ok;
|
||||
}
|
||||
if (type.equals("uri") || type.equals("oid") || type.equals("uuid") || type.equals("url") || type.equals("canonical")) {
|
||||
String url = e.primitiveValue();
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !url.startsWith("oid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URI_OID) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !url.startsWith("uuid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URI_UUID) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.equals(Utilities.trimWS(url).replace(" ", ""))
|
||||
// work around an old invalid example in a core package
|
||||
|| "http://www.acme.com/identifiers/patient or urn:ietf:rfc:3986 if the Identifier.value itself is a full uri".equals(url), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URI_WS, url) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || url.length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && 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;
|
||||
|
||||
if (type.equals("oid")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.startsWith("urn:oid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_OID_START) && ok;
|
||||
}
|
||||
if (type.equals("uuid")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.startsWith("urn:uuid:"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_UUID_STRAT) && ok;
|
||||
}
|
||||
if (type.equals("canonical")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, url.startsWith("#") || Utilities.isAbsoluteUrl(url), I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE, url) && ok;
|
||||
}
|
||||
|
||||
if (url != null && url.startsWith("urn:uuid:")) {
|
||||
String s = url.substring(9);
|
||||
if (s.contains("#")) {
|
||||
s = s.substring(0, s.indexOf("#"));
|
||||
}
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isValidUUID(s), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_UUID_VALID, s) && ok;
|
||||
}
|
||||
if (url != null && url.startsWith("urn:oid:")) {
|
||||
String cc = url.substring(8);
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
|
||||
// OIDs roots shorter than 4 chars are almost never valid for namespaces except for 1.3.x
|
||||
Utilities.isOid(cc) && ((cc.lastIndexOf('.') >= 4 || cc.startsWith("1.3"))),
|
||||
I18nConstants.TYPE_SPECIFIC_CHECKS_DT_OID_VALID, cc) && ok;
|
||||
}
|
||||
|
||||
if (isCanonicalURLElement(e, node)) {
|
||||
// we get to here if this is a defining canonical URL (e.g. CodeSystem.url)
|
||||
// the URL must be an IRI if present
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isAbsoluteUrl(url),
|
||||
node.isContained() ? I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_CONTAINED : I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE, url) && ok;
|
||||
} else if (!e.getProperty().getDefinition().getPath().equals("Bundle.entry.fullUrl")) { // we don't check fullUrl here; it's not a reference, it's a definition. It'll get checked as part of checking the bundle
|
||||
ok = validateReference(valContext, errors, path, type, context, e, url) && ok;
|
||||
}
|
||||
}
|
||||
if (type.equals(ID) && !"Resource.id".equals(context.getBase().getPath())) {
|
||||
// work around an old issue with ElementDefinition.id
|
||||
if (!context.getPath().equals("ElementDefinition.id")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, FormatUtilities.isValidId(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ID_VALID, e.primitiveValue()) && ok;
|
||||
}
|
||||
}
|
||||
if (type.equalsIgnoreCase("string") && e.hasPrimitiveValue()) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue() == null || e.primitiveValue().length() > 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_NOTEMPTY)) {
|
||||
if (warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue() == null || !Utilities.isAllWhitespace(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_STRING_WS_ALL, prepWSPresentation(e.primitiveValue()))) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue() == null || Utilities.trimWS(e.primitiveValue()).equals(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_STRING_WS, prepWSPresentation(e.primitiveValue()));
|
||||
}
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.primitiveValue().length() <= 1048576, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_STRING_LENGTH)) {
|
||||
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;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (type.equals("dateTime")) {
|
||||
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;
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("tz-for-time"))) {
|
||||
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());
|
||||
if (isCoreDefinition(profile) || !context.hasExtension(ToolingExtensions.EXT_DATE_RULES) || ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid")) {
|
||||
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;
|
||||
if (type.equals("dateTime")) {
|
||||
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;
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("tz-for-time"))) {
|
||||
dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !hasTime(e.primitiveValue()) || hasTimeZone(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DATETIME_TZ) && dok;
|
||||
}
|
||||
}
|
||||
ok = ok && dok;
|
||||
}
|
||||
if (type.equals("time")) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path,
|
||||
e.primitiveValue()
|
||||
.matches("([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_TIME_VALID) && ok;
|
||||
try {
|
||||
TimeType dt = new TimeType(e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_TIME_VALID, ex.getMessage());
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (type.equals("date")) {
|
||||
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());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
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();
|
||||
if (isNotBlank(encoded)) {
|
||||
boolean bok = Base64Util.isValidBase64(encoded);
|
||||
if (!bok) {
|
||||
String value = encoded.length() < 100 ? encoded : "(snip)";
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_VALID, value) && ok;
|
||||
} else {
|
||||
boolean wsok = !Base64Util.base64HasWhitespace(encoded);
|
||||
if (VersionUtilities.isR5VerOrLater(this.context.getVersion())) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, wsok, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR) && ok;
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, wsok, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING);
|
||||
}
|
||||
}
|
||||
if (bok && context.hasExtension(ToolingExtensions.EXT_MAX_SIZE)) {
|
||||
int size = Base64Util.countBase64DecodedBytes(encoded);
|
||||
long def = Long.parseLong(ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_MAX_SIZE));
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, e.line(), e.col(), path, size <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_TOO_LONG, size, def) && ok;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (type.equals("integer") || type.equals("unsignedInt") || type.equals("positiveInt")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isInteger(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_VALID, e.primitiveValue())) {
|
||||
Integer v = Integer.valueOf(e.getValue());
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueIntegerType() || !context.getMaxValueIntegerType().hasValue() || (context.getMaxValueIntegerType().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueIntegerType() ? context.getMaxValueIntegerType() : "")) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueIntegerType() || !context.getMinValueIntegerType().hasValue() || (context.getMinValueIntegerType().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueIntegerType() ? context.getMinValueIntegerType() : "")) && ok;
|
||||
if (type.equals("unsignedInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v >= 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT0) && ok;
|
||||
if (type.equals("positiveInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v > 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT1) && ok;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (type.equals("integer64")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isLong(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER64_VALID, e.primitiveValue())) {
|
||||
Long v = Long.valueOf(e.getValue());
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueInteger64Type() || !context.getMaxValueInteger64Type().hasValue() || (context.getMaxValueInteger64Type().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueInteger64Type() ? context.getMaxValueInteger64Type() : "")) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueInteger64Type() || !context.getMinValueInteger64Type().hasValue() || (context.getMinValueInteger64Type().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueInteger64Type() ? context.getMinValueInteger64Type() : "")) && ok;
|
||||
if (type.equals("unsignedInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v >= 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT0) && ok;
|
||||
if (type.equals("positiveInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v > 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT1) && ok;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (type.equals("decimal")) {
|
||||
if (e.primitiveValue() != null) {
|
||||
DecimalStatus ds = Utilities.checkDecimal(e.primitiveValue(), true, false);
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, ds == DecimalStatus.OK || ds == DecimalStatus.RANGE, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_VALID, e.primitiveValue())) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.VALUE, e.line(), e.col(), path, ds != DecimalStatus.RANGE, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_RANGE, e.primitiveValue());
|
||||
try {
|
||||
Decimal v = new Decimal(e.getValue());
|
||||
if (context.hasMaxValueDecimalType() && context.getMaxValueDecimalType().hasValue()) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMaxValue(v, context.getMaxValueDecimalType().getValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_GT, context.getMaxValueDecimalType()) && ok;
|
||||
} else if (context.hasMaxValueIntegerType() && context.getMaxValueIntegerType().hasValue()) {
|
||||
// users can also provide a max integer type. It's not clear whether that's actually valid, but we'll check for it anyway
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMaxValue(v, new BigDecimal(context.getMaxValueIntegerType().getValue())), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_GT, context.getMaxValueIntegerType()) && ok;
|
||||
}
|
||||
|
||||
if (context.hasMinValueDecimalType() && context.getMinValueDecimalType().hasValue()) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMinValue(v, context.getMinValueDecimalType().getValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_LT, context.getMinValueDecimalType()) && ok;
|
||||
} else if (context.hasMinValueIntegerType() && context.getMinValueIntegerType().hasValue()) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMinValue(v, new BigDecimal(context.getMinValueIntegerType().getValue())), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_LT, context.getMinValueIntegerType()) && ok;
|
||||
dok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxLength() || context.getMaxLength() == 0 || e.primitiveValue().length() <= context.getMaxLength(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_LENGTH, context.getMaxLength()) && dok;
|
||||
if (dok) {
|
||||
try {
|
||||
DateTimeType dt = new DateTimeType(e.primitiveValue());
|
||||
if (isCoreDefinition(profile) || !context.hasExtension(ToolingExtensions.EXT_DATE_RULES) || ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid")) {
|
||||
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) {
|
||||
// should never happen?
|
||||
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,
|
||||
e.primitiveValue()
|
||||
.matches("([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)"), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_TIME_VALID) && ok;
|
||||
try {
|
||||
TimeType dt = new TimeType(e.primitiveValue());
|
||||
} catch (Exception ex) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_TIME_VALID, ex.getMessage());
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (type.equals("date")) {
|
||||
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());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
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();
|
||||
if (isNotBlank(encoded)) {
|
||||
boolean bok = Base64Util.isValidBase64(encoded);
|
||||
if (!bok) {
|
||||
String value = encoded.length() < 100 ? encoded : "(snip)";
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_VALID, value) && ok;
|
||||
} else {
|
||||
boolean wsok = !Base64Util.base64HasWhitespace(encoded);
|
||||
if (VersionUtilities.isR5VerOrLater(this.context.getVersion())) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, wsok, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR) && ok;
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, wsok, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING);
|
||||
}
|
||||
}
|
||||
if (bok && context.hasExtension(ToolingExtensions.EXT_MAX_SIZE)) {
|
||||
int size = Base64Util.countBase64DecodedBytes(encoded);
|
||||
long def = Long.parseLong(ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_MAX_SIZE));
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, e.line(), e.col(), path, size <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_TOO_LONG, size, def) && ok;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (type.equals("integer") || type.equals("unsignedInt") || type.equals("positiveInt")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isInteger(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_VALID, e.primitiveValue())) {
|
||||
Integer v = Integer.valueOf(e.getValue());
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueIntegerType() || !context.getMaxValueIntegerType().hasValue() || (context.getMaxValueIntegerType().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueIntegerType() ? context.getMaxValueIntegerType() : "")) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueIntegerType() || !context.getMinValueIntegerType().hasValue() || (context.getMinValueIntegerType().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueIntegerType() ? context.getMinValueIntegerType() : "")) && ok;
|
||||
if (type.equals("unsignedInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v >= 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT0) && ok;
|
||||
if (type.equals("positiveInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v > 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT1) && ok;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (context.hasExtension(ToolingExtensions.EXT_MAX_DECIMALS)) {
|
||||
int dp = e.primitiveValue().contains(".") ? e.primitiveValue().substring(e.primitiveValue().indexOf(".")+1).length() : 0;
|
||||
int def = Integer.parseInt(ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_MAX_DECIMALS));
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, e.line(), e.col(), path, dp <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_CHARS, dp, def) && ok;
|
||||
}
|
||||
}
|
||||
if (type.equals("instant")) {
|
||||
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());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
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) {
|
||||
// Technically, a code is restricted to string which has at least one character and no leading or trailing whitespace, and where there is no whitespace
|
||||
// other than single spaces in the contents
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, passesCodeWhitespaceRules(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CODE_WS, e.primitiveValue()) && 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;
|
||||
}
|
||||
|
||||
if (context.hasBinding() && e.primitiveValue() != null) {
|
||||
// special cases
|
||||
if ("StructureDefinition.type".equals(context.getPath()) && "http://hl7.org/fhir/StructureDefinition/StructureDefinition".equals(profile.getUrl())) {
|
||||
ok = checkTypeValue(errors, path, e, parentNode.getElement());
|
||||
} else {
|
||||
ok = checkPrimitiveBinding(valContext, errors, path, type, context, e, profile, node) && ok;
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals("markdown") && htmlInMarkdownCheck != HtmlInMarkdownCheck.NONE) {
|
||||
String raw = e.primitiveValue();
|
||||
String processed = MarkDownProcessor.preProcess(raw);
|
||||
if (!raw.equals(processed)) {
|
||||
int i = 0;
|
||||
while (i < raw.length() && raw.charAt(1) == processed.charAt(i)) {
|
||||
i++;
|
||||
}
|
||||
if (i < raw.length()-1 ) {
|
||||
if (!warningOrError(htmlInMarkdownCheck == HtmlInMarkdownCheck.ERROR, errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_MARKDOWN_HTML, raw.subSequence(i, i+2))) {
|
||||
ok = (htmlInMarkdownCheck != HtmlInMarkdownCheck.ERROR) && ok;
|
||||
}
|
||||
if (type.equals("integer64")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isLong(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER64_VALID, e.primitiveValue())) {
|
||||
Long v = Long.valueOf(e.getValue());
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueInteger64Type() || !context.getMaxValueInteger64Type().hasValue() || (context.getMaxValueInteger64Type().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueInteger64Type() ? context.getMaxValueInteger64Type() : "")) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueInteger64Type() || !context.getMinValueInteger64Type().hasValue() || (context.getMinValueInteger64Type().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueInteger64Type() ? context.getMinValueInteger64Type() : "")) && ok;
|
||||
if (type.equals("unsignedInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v >= 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT0) && ok;
|
||||
if (type.equals("positiveInt"))
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, v > 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT1) && ok;
|
||||
} else {
|
||||
if (!warningOrError(htmlInMarkdownCheck == HtmlInMarkdownCheck.ERROR, errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_MARKDOWN_HTML, raw)) {
|
||||
ok = (htmlInMarkdownCheck != HtmlInMarkdownCheck.ERROR) && ok;
|
||||
}
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type.equals("xhtml")) {
|
||||
XhtmlNode xhtml = e.getXhtml();
|
||||
if (xhtml != null) { // if it is null, this is an error already noted in the parsers
|
||||
// check that the namespace is there and correct.
|
||||
String ns = xhtml.getNsDecl();
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, FormatUtilities.XHTML_NS.equals(ns), I18nConstants.XHTML_XHTML_NS_INVALID, ns, FormatUtilities.XHTML_NS) && ok;
|
||||
// check that inner namespaces are all correct
|
||||
ok = checkInnerNS(errors, e, path, xhtml.getChildNodes()) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, "div".equals(xhtml.getName()), I18nConstants.XHTML_XHTML_NAME_INVALID, xhtml.getName()) && ok;
|
||||
// check that no illegal elements and attributes have been used
|
||||
ok = checkInnerNames(errors, e, path, xhtml.getChildNodes(), false) && ok;
|
||||
ok = checkUrls(errors, e, path, xhtml.getChildNodes()) && ok;
|
||||
ok = checkIdRefs(errors, e, path, xhtml, resource, node) && ok;
|
||||
if (true) {
|
||||
ok = checkReferences(valContext, errors, e, path, "div", xhtml, resource) && ok;
|
||||
if (type.equals("decimal")) {
|
||||
if (e.primitiveValue() != null) {
|
||||
DecimalStatus ds = Utilities.checkDecimal(e.primitiveValue(), true, false);
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, ds == DecimalStatus.OK || ds == DecimalStatus.RANGE, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_VALID, e.primitiveValue())) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.VALUE, e.line(), e.col(), path, ds != DecimalStatus.RANGE, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_RANGE, e.primitiveValue());
|
||||
try {
|
||||
Decimal v = new Decimal(e.getValue());
|
||||
if (context.hasMaxValueDecimalType() && context.getMaxValueDecimalType().hasValue()) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMaxValue(v, context.getMaxValueDecimalType().getValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_GT, context.getMaxValueDecimalType()) && ok;
|
||||
} else if (context.hasMaxValueIntegerType() && context.getMaxValueIntegerType().hasValue()) {
|
||||
// users can also provide a max integer type. It's not clear whether that's actually valid, but we'll check for it anyway
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMaxValue(v, new BigDecimal(context.getMaxValueIntegerType().getValue())), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_GT, context.getMaxValueIntegerType()) && ok;
|
||||
}
|
||||
|
||||
if (context.hasMinValueDecimalType() && context.getMinValueDecimalType().hasValue()) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMinValue(v, context.getMinValueDecimalType().getValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_LT, context.getMinValueDecimalType()) && ok;
|
||||
} else if (context.hasMinValueIntegerType() && context.getMinValueIntegerType().hasValue()) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, checkDecimalMinValue(v, new BigDecimal(context.getMinValueIntegerType().getValue())), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_LT, context.getMinValueIntegerType()) && ok;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// should never happen?
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (true) {
|
||||
ok = checkImageSources(valContext, errors, e, path, "div", xhtml, resource) && ok;
|
||||
if (context.hasExtension(ToolingExtensions.EXT_MAX_DECIMALS)) {
|
||||
int dp = e.primitiveValue().contains(".") ? e.primitiveValue().substring(e.primitiveValue().indexOf(".")+1).length() : 0;
|
||||
int def = Integer.parseInt(ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_MAX_DECIMALS));
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, e.line(), e.col(), path, dp <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_DECIMAL_CHARS, dp, def) && ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.hasFixed()) {
|
||||
ok = checkFixedValue(errors, path, e, context.getFixed(), profile.getVersionedUrl(), context.getSliceName(), null, false, profile.getVersionedUrl()+"#"+context.getId()) && ok;
|
||||
}
|
||||
if (context.hasPattern()) {
|
||||
ok = checkFixedValue(errors, path, e, context.getPattern(), profile.getVersionedUrl(), context.getSliceName(), null, true, profile.getVersionedUrl()+"#"+context.getId()) && ok;
|
||||
}
|
||||
|
||||
if (ok && !ID_EXEMPT_LIST.contains(e.fhirType())) { // ids get checked elsewhere
|
||||
String regext = FHIRPathExpressionFixer.fixRegex(getRegexFromType(e.fhirType()));
|
||||
if (regext != null) {
|
||||
try {
|
||||
String pt = e.primitiveValue();
|
||||
String ptFmt = null;
|
||||
if (e.getProperty().getDefinition().hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) {
|
||||
ptFmt = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(e.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT), pt);
|
||||
if (type.equals("instant")) {
|
||||
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());
|
||||
if (isCoreDefinition(profile) || (context.hasExtension(ToolingExtensions.EXT_DATE_RULES) && ToolingExtensions.readStringExtension(context, ToolingExtensions.EXT_DATE_RULES).contains("year-valid"))) {
|
||||
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;
|
||||
}
|
||||
boolean matches = pt.matches(regext) || (ptFmt != null && ptFmt.matches(regext));
|
||||
if (!matches) {
|
||||
if (ptFmt == null) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, matches, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX_TYPE, pt, e.fhirType(), regext) && ok;
|
||||
} else {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, matches, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX_TYPE_ALT, pt, ptFmt, e.fhirType(), regext) && ok;
|
||||
}
|
||||
ok = ok && dok;
|
||||
}
|
||||
|
||||
if (type.equals("code") && e.primitiveValue() != null) {
|
||||
// Technically, a code is restricted to string which has at least one character and no leading or trailing whitespace, and where there is no whitespace
|
||||
// other than single spaces in the contents
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, passesCodeWhitespaceRules(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CODE_WS, e.primitiveValue()) && 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;
|
||||
}
|
||||
|
||||
if (context.hasBinding() && e.primitiveValue() != null) {
|
||||
// special cases
|
||||
if ("StructureDefinition.type".equals(context.getPath()) && "http://hl7.org/fhir/StructureDefinition/StructureDefinition".equals(profile.getUrl())) {
|
||||
ok = checkTypeValue(errors, path, e, parentNode.getElement());
|
||||
} else {
|
||||
ok = checkPrimitiveBinding(valContext, errors, path, type, context, e, profile, node) && ok;
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals("markdown") && htmlInMarkdownCheck != HtmlInMarkdownCheck.NONE) {
|
||||
String raw = e.primitiveValue();
|
||||
String processed = MarkDownProcessor.preProcess(raw);
|
||||
if (!raw.equals(processed)) {
|
||||
int i = 0;
|
||||
while (i < raw.length() && raw.charAt(1) == processed.charAt(i)) {
|
||||
i++;
|
||||
}
|
||||
if (i < raw.length()-1 ) {
|
||||
if (!warningOrError(htmlInMarkdownCheck == HtmlInMarkdownCheck.ERROR, errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_MARKDOWN_HTML, raw.subSequence(i, i+2))) {
|
||||
ok = (htmlInMarkdownCheck != HtmlInMarkdownCheck.ERROR) && ok;
|
||||
}
|
||||
} else {
|
||||
if (!warningOrError(htmlInMarkdownCheck == HtmlInMarkdownCheck.ERROR, errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_MARKDOWN_HTML, raw)) {
|
||||
ok = (htmlInMarkdownCheck != HtmlInMarkdownCheck.ERROR) && ok;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX_EXCEPTION, regext, e.fhirType(), ex.getMessage()) && ok;
|
||||
}
|
||||
}
|
||||
if (type.equals("xhtml")) {
|
||||
XhtmlNode xhtml = e.getXhtml();
|
||||
if (xhtml != null) { // if it is null, this is an error already noted in the parsers
|
||||
// check that the namespace is there and correct.
|
||||
String ns = xhtml.getNsDecl();
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, FormatUtilities.XHTML_NS.equals(ns), I18nConstants.XHTML_XHTML_NS_INVALID, ns, FormatUtilities.XHTML_NS) && ok;
|
||||
// check that inner namespaces are all correct
|
||||
ok = checkInnerNS(errors, e, path, xhtml.getChildNodes()) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, "div".equals(xhtml.getName()), I18nConstants.XHTML_XHTML_NAME_INVALID, xhtml.getName()) && ok;
|
||||
// check that no illegal elements and attributes have been used
|
||||
ok = checkInnerNames(errors, e, path, xhtml.getChildNodes(), false) && ok;
|
||||
ok = checkUrls(errors, e, path, xhtml.getChildNodes()) && ok;
|
||||
ok = checkIdRefs(errors, e, path, xhtml, resource, node) && ok;
|
||||
if (true) {
|
||||
ok = checkReferences(valContext, errors, e, path, "div", xhtml, resource) && ok;
|
||||
}
|
||||
if (true) {
|
||||
ok = checkImageSources(valContext, errors, e, path, "div", xhtml, resource) && ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.hasFixed()) {
|
||||
ok = checkFixedValue(errors, path, e, context.getFixed(), profile.getVersionedUrl(), context.getSliceName(), null, false, profile.getVersionedUrl()+"#"+context.getId()) && ok;
|
||||
}
|
||||
if (context.hasPattern()) {
|
||||
ok = checkFixedValue(errors, path, e, context.getPattern(), profile.getVersionedUrl(), context.getSliceName(), null, true, profile.getVersionedUrl()+"#"+context.getId()) && ok;
|
||||
}
|
||||
|
||||
if (ok && !ID_EXEMPT_LIST.contains(e.fhirType())) { // ids get checked elsewhere
|
||||
String regext = FHIRPathExpressionFixer.fixRegex(getRegexFromType(e.fhirType()));
|
||||
if (regext != null) {
|
||||
try {
|
||||
String pt = e.primitiveValue();
|
||||
String ptFmt = null;
|
||||
if (e.getProperty().getDefinition().hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) {
|
||||
ptFmt = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(e.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT), pt);
|
||||
}
|
||||
boolean matches = pt.matches(regext) || (ptFmt != null && ptFmt.matches(regext));
|
||||
if (!matches) {
|
||||
if (ptFmt == null) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, matches, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX_TYPE, pt, e.fhirType(), regext) && ok;
|
||||
} else {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, matches, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX_TYPE_ALT, pt, ptFmt, e.fhirType(), regext) && ok;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_REGEX_EXCEPTION, regext, e.fhirType(), ex.getMessage()) && ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for nothing to check
|
||||
return ok;
|
||||
}
|
||||
@ -7618,7 +7673,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
*/
|
||||
private boolean validateResource(ValidationContext valContext, List<ValidationMessage> errors, Element resource,
|
||||
Element element, StructureDefinition defn, IdStatus idstatus, NodeStack stack, PercentageTracker pct, ValidationMode mode, boolean forReference, boolean fromContained) throws FHIRException {
|
||||
|
||||
boolean ok = true;
|
||||
// check here if we call validation policy here, and then change it to the new interface
|
||||
assert stack != null;
|
||||
@ -7669,6 +7723,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean isMatcheType = false;
|
||||
if (element.hasExtension("http://hl7.org/fhir/tools/StructureDefinition/matchetype")) {
|
||||
Element ext = element.getExtension("http://hl7.org/fhir/tools/StructureDefinition/matchetype");
|
||||
isMatcheType = "true".equals(ext.getNamedChildValue("value"));
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), matchetypeStatus != MatchetypeStatus.Disallowed, I18nConstants.RESOURCE_MATCHETYPE_DISALLOWED) && ok;
|
||||
|
||||
} else {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), matchetypeStatus != MatchetypeStatus.Required, I18nConstants.RESOURCE_MATCHETYPE_REQUIRED) && ok;
|
||||
}
|
||||
valContext.setMatchetype(isMatcheType);
|
||||
|
||||
// validate
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), checkResourceName(defn, resourceName, element.getFormat()), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE,
|
||||
defn.getType(), resourceName, defn.getVersionedUrl())) {
|
||||
@ -8265,5 +8330,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
public void setCacheFolder(String cacheFolder) {
|
||||
this.cacheFolder = cacheFolder;
|
||||
}
|
||||
|
||||
public MatchetypeStatus getMatchetypeStatus() {
|
||||
return matchetypeStatus;
|
||||
}
|
||||
|
||||
public void setMatchetypeStatus(MatchetypeStatus matchetypeStatus) {
|
||||
this.matchetypeStatus = matchetypeStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,242 +7,256 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
public class ValidationContext {
|
||||
|
||||
public static final String INTERNAL_REFERENCES_NAME = "internal.references";
|
||||
public static final String INTERNAL_REFERENCES_NAME = "internal.references";
|
||||
|
||||
private Object appContext;
|
||||
private Object appContext;
|
||||
|
||||
// the version we are currently validating for right now
|
||||
// not implemented yet - this is the forerunner of a major upgrade to the validator
|
||||
private String version;
|
||||
|
||||
// the resource we are actually validating right now
|
||||
private Element resource;
|
||||
// the resource that is the scope of id resolution - either the same as resource, or the resource the contains that resource. This can only be one level deep.
|
||||
private Element rootResource;
|
||||
private Element groupingResource; // either a bundle or a parameters that holds the rootResource (for reference resolution)
|
||||
|
||||
private StructureDefinition profile; // the profile that contains the content being validated
|
||||
|
||||
private boolean checkSpecials = true;
|
||||
private Map<String, List<ValidationMessage>> sliceRecords;
|
||||
private Set<String> internalRefs;
|
||||
|
||||
public ValidationContext(Object appContext) {
|
||||
this.appContext = appContext;
|
||||
}
|
||||
// the version we are currently validating for right now
|
||||
// not implemented yet - this is the forerunner of a major upgrade to the validator
|
||||
private String version;
|
||||
|
||||
public ValidationContext(Object appContext, Element element) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = element;
|
||||
this.internalRefs = setupInternalRefs(element);
|
||||
check();
|
||||
|
||||
// no groupingResource (Bundle or Parameters)
|
||||
dump("creating");
|
||||
// the resource we are actually validating right now
|
||||
private Element resource;
|
||||
// the resource that is the scope of id resolution - either the same as resource, or the resource the contains that resource. This can only be one level deep.
|
||||
private Element rootResource;
|
||||
private Element groupingResource; // either a bundle or a parameters that holds the rootResource (for reference resolution)
|
||||
|
||||
private StructureDefinition profile; // the profile that contains the content being validated
|
||||
|
||||
private boolean checkSpecials = true;
|
||||
private Map<String, List<ValidationMessage>> sliceRecords;
|
||||
private Set<String> internalRefs;
|
||||
private boolean matchetype;
|
||||
|
||||
public ValidationContext(Object appContext) {
|
||||
this.appContext = appContext;
|
||||
}
|
||||
|
||||
private Set<String> setupInternalRefs(Element element) {
|
||||
Set<String> res = (Set<String>) element.getUserData(INTERNAL_REFERENCES_NAME);
|
||||
if (res == null) {
|
||||
res = new HashSet<String>();
|
||||
element.setUserData(INTERNAL_REFERENCES_NAME, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public ValidationContext(Object appContext, Element element) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = element;
|
||||
this.internalRefs = setupInternalRefs(element);
|
||||
check();
|
||||
|
||||
private void check() {
|
||||
if (!rootResource.hasParentForValidator()) {
|
||||
throw new Error("No parent on root resource");
|
||||
}
|
||||
}
|
||||
|
||||
public ValidationContext(Object appContext, Element element, Element root) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = root;
|
||||
this.internalRefs = setupInternalRefs(element);
|
||||
check();
|
||||
// no groupingResource (Bundle or Parameters)
|
||||
dump("creating");
|
||||
// no groupingResource (Bundle or Parameters)
|
||||
dump("creating");
|
||||
}
|
||||
|
||||
public ValidationContext(Object appContext, Element element, Element root, Element groupingResource) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = root;
|
||||
this.groupingResource = groupingResource;
|
||||
this.internalRefs = setupInternalRefs(element);
|
||||
check();
|
||||
dump("creating");
|
||||
private Set<String> setupInternalRefs(Element element) {
|
||||
Set<String> res = (Set<String>) element.getUserData(INTERNAL_REFERENCES_NAME);
|
||||
if (res == null) {
|
||||
res = new HashSet<String>();
|
||||
element.setUserData(INTERNAL_REFERENCES_NAME, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public Object getAppContext() {
|
||||
return appContext;
|
||||
private void check() {
|
||||
if (!rootResource.hasParentForValidator()) {
|
||||
throw new Error("No parent on root resource");
|
||||
}
|
||||
}
|
||||
|
||||
public ValidationContext setAppContext(Object appContext) {
|
||||
this.appContext = appContext;
|
||||
return this;
|
||||
}
|
||||
public ValidationContext(Object appContext, Element element, Element root) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = root;
|
||||
this.internalRefs = setupInternalRefs(element);
|
||||
check();
|
||||
// no groupingResource (Bundle or Parameters)
|
||||
dump("creating");
|
||||
}
|
||||
|
||||
public ValidationContext setResource(Element resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
public ValidationContext(Object appContext, Element element, Element root, Element groupingResource) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = root;
|
||||
this.groupingResource = groupingResource;
|
||||
this.internalRefs = setupInternalRefs(element);
|
||||
check();
|
||||
dump("creating");
|
||||
}
|
||||
|
||||
public Element getRootResource() {
|
||||
return rootResource;
|
||||
}
|
||||
public Object getAppContext() {
|
||||
return appContext;
|
||||
}
|
||||
|
||||
public ValidationContext setRootResource(Element rootResource) {
|
||||
this.rootResource = rootResource;
|
||||
dump("setting root resource");
|
||||
return this;
|
||||
}
|
||||
public ValidationContext setAppContext(Object appContext) {
|
||||
this.appContext = appContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getGroupingResource() {
|
||||
return groupingResource;
|
||||
}
|
||||
public ValidationContext setResource(Element resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StructureDefinition getProfile() {
|
||||
return profile;
|
||||
}
|
||||
public Element getRootResource() {
|
||||
return rootResource;
|
||||
}
|
||||
|
||||
public ValidationContext setProfile(StructureDefinition profile) {
|
||||
this.profile = profile;
|
||||
return this;
|
||||
}
|
||||
public ValidationContext setRootResource(Element rootResource) {
|
||||
this.rootResource = rootResource;
|
||||
dump("setting root resource");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, List<ValidationMessage>> getSliceRecords() {
|
||||
return sliceRecords;
|
||||
}
|
||||
public Element getGroupingResource() {
|
||||
return groupingResource;
|
||||
}
|
||||
|
||||
public ValidationContext setSliceRecords(Map<String, List<ValidationMessage>> sliceRecords) {
|
||||
this.sliceRecords = sliceRecords;
|
||||
return this;
|
||||
}
|
||||
public StructureDefinition getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public boolean isCheckSpecials() {
|
||||
return checkSpecials;
|
||||
}
|
||||
public ValidationContext setProfile(StructureDefinition profile) {
|
||||
this.profile = profile;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setCheckSpecials(boolean checkSpecials) {
|
||||
this.checkSpecials = checkSpecials;
|
||||
}
|
||||
public Map<String, List<ValidationMessage>> getSliceRecords() {
|
||||
return sliceRecords;
|
||||
}
|
||||
|
||||
public Element getResource() {
|
||||
return resource;
|
||||
}
|
||||
public ValidationContext setSliceRecords(Map<String, List<ValidationMessage>> sliceRecords) {
|
||||
this.sliceRecords = sliceRecords;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void sliceNotes(String url, List<ValidationMessage> record) {
|
||||
if (sliceRecords != null) {
|
||||
sliceRecords.put(url, record);
|
||||
}
|
||||
}
|
||||
public boolean isCheckSpecials() {
|
||||
return checkSpecials;
|
||||
}
|
||||
|
||||
public ValidationContext forContained(Element element) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.rootResource = resource;
|
||||
res.resource = element;
|
||||
res.profile = profile;
|
||||
res.groupingResource = groupingResource;
|
||||
res.version = version;
|
||||
res.internalRefs = setupInternalRefs(element);
|
||||
res.dump("forContained");
|
||||
return res;
|
||||
}
|
||||
public void setCheckSpecials(boolean checkSpecials) {
|
||||
this.checkSpecials = checkSpecials;
|
||||
}
|
||||
|
||||
public ValidationContext forEntry(Element element, Element groupingResource) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.rootResource = element;
|
||||
res.resource = element;
|
||||
res.profile = profile;
|
||||
res.groupingResource = groupingResource;
|
||||
res.version = version;
|
||||
res.internalRefs = setupInternalRefs(element);
|
||||
res.dump("forEntry");
|
||||
return res;
|
||||
}
|
||||
public Element getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public ValidationContext forProfile(StructureDefinition profile) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = rootResource;
|
||||
res.profile = profile;
|
||||
res.version = version;
|
||||
res.groupingResource = groupingResource;
|
||||
res.internalRefs = internalRefs;
|
||||
res.sliceRecords = sliceRecords != null ? sliceRecords : new HashMap<String, List<ValidationMessage>>();
|
||||
res.dump("forProfile "+profile.getUrl());
|
||||
return res;
|
||||
public void sliceNotes(String url, List<ValidationMessage> record) {
|
||||
if (sliceRecords != null) {
|
||||
sliceRecords.put(url, record);
|
||||
}
|
||||
}
|
||||
|
||||
public ValidationContext forLocalReference(StructureDefinition profile, Element resource) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.profile = profile;
|
||||
res.groupingResource = groupingResource;
|
||||
res.checkSpecials = false;
|
||||
res.internalRefs = setupInternalRefs(resource);
|
||||
res.dump("forLocalReference "+profile.getUrl());
|
||||
res.version = version;
|
||||
return res;
|
||||
}
|
||||
public ValidationContext forContained(Element element) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.rootResource = resource;
|
||||
res.resource = element;
|
||||
res.profile = profile;
|
||||
res.groupingResource = groupingResource;
|
||||
res.version = version;
|
||||
res.matchetype = matchetype;
|
||||
res.internalRefs = setupInternalRefs(element);
|
||||
res.dump("forContained");
|
||||
return res;
|
||||
}
|
||||
|
||||
private void dump(String ctxt) {
|
||||
// System.out.println("** app = "+(appContext == null ? "(null)" : appContext.toString())+", res = "+resource.toString()+", root = "+rootResource.toString()+" ("+ctxt+")");
|
||||
// if (rootResource.getName().equals("contained")) {
|
||||
// System.out.println("** something is wrong!");
|
||||
// }
|
||||
}
|
||||
public ValidationContext forEntry(Element element, Element groupingResource) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.rootResource = element;
|
||||
res.resource = element;
|
||||
res.profile = profile;
|
||||
res.groupingResource = groupingResource;
|
||||
res.version = version;
|
||||
res.matchetype = matchetype;
|
||||
res.internalRefs = setupInternalRefs(element);
|
||||
res.dump("forEntry");
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidationContext forRemoteReference(StructureDefinition profile, Element resource) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.profile = profile;
|
||||
res.groupingResource = null;
|
||||
res.checkSpecials = false;
|
||||
res.version = version;
|
||||
res.internalRefs = setupInternalRefs(resource);
|
||||
res.dump("forRemoteReference "+profile.getUrl());
|
||||
return res;
|
||||
}
|
||||
public ValidationContext forProfile(StructureDefinition profile) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = rootResource;
|
||||
res.profile = profile;
|
||||
res.version = version;
|
||||
res.matchetype = matchetype;
|
||||
res.groupingResource = groupingResource;
|
||||
res.internalRefs = internalRefs;
|
||||
res.sliceRecords = sliceRecords != null ? sliceRecords : new HashMap<String, List<ValidationMessage>>();
|
||||
res.dump("forProfile "+profile.getUrl());
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidationContext forSlicing() {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = rootResource;
|
||||
res.groupingResource = groupingResource;
|
||||
res.profile = profile;
|
||||
res.checkSpecials = false;
|
||||
res.version = version;
|
||||
res.internalRefs = internalRefs;
|
||||
res.sliceRecords = new HashMap<String, List<ValidationMessage>>();
|
||||
res.dump("forSlicing");
|
||||
return res;
|
||||
}
|
||||
public ValidationContext forLocalReference(StructureDefinition profile, Element resource) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.profile = profile;
|
||||
res.groupingResource = groupingResource;
|
||||
res.checkSpecials = false;
|
||||
res.matchetype = matchetype;
|
||||
res.internalRefs = setupInternalRefs(resource);
|
||||
res.dump("forLocalReference "+profile.getUrl());
|
||||
res.version = version;
|
||||
return res;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
private void dump(String ctxt) {
|
||||
// System.out.println("** app = "+(appContext == null ? "(null)" : appContext.toString())+", res = "+resource.toString()+", root = "+rootResource.toString()+" ("+ctxt+")");
|
||||
// if (rootResource.getName().equals("contained")) {
|
||||
// System.out.println("** something is wrong!");
|
||||
// }
|
||||
}
|
||||
|
||||
public ValidationContext setVersion(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
public ValidationContext forRemoteReference(StructureDefinition profile, Element resource) {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.profile = profile;
|
||||
res.groupingResource = null;
|
||||
res.checkSpecials = false;
|
||||
res.version = version;
|
||||
res.matchetype = matchetype;
|
||||
res.internalRefs = setupInternalRefs(resource);
|
||||
res.dump("forRemoteReference "+profile.getUrl());
|
||||
return res;
|
||||
}
|
||||
|
||||
public Set<String> getInternalRefs() {
|
||||
return internalRefs;
|
||||
}
|
||||
public ValidationContext forSlicing() {
|
||||
ValidationContext res = new ValidationContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = rootResource;
|
||||
res.groupingResource = groupingResource;
|
||||
res.profile = profile;
|
||||
res.checkSpecials = false;
|
||||
res.version = version;
|
||||
res.matchetype = matchetype;
|
||||
res.internalRefs = internalRefs;
|
||||
res.sliceRecords = new HashMap<String, List<ValidationMessage>>();
|
||||
res.dump("forSlicing");
|
||||
return res;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public ValidationContext setVersion(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getInternalRefs() {
|
||||
return internalRefs;
|
||||
}
|
||||
|
||||
public boolean isMatchetype() {
|
||||
return matchetype;
|
||||
}
|
||||
|
||||
public void setMatchetype(boolean matchetype) {
|
||||
this.matchetype = matchetype;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -85,6 +85,7 @@ import org.hl7.fhir.validation.ValidatorUtils;
|
||||
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
|
||||
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator.MatchetypeStatus;
|
||||
import org.hl7.fhir.validation.instance.advisor.BasePolicyAdvisorForFullValidation;
|
||||
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
||||
import org.junit.AfterClass;
|
||||
@ -371,6 +372,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||
if (content.has("noHtmlInMarkdown")) {
|
||||
val.setHtmlInMarkdownCheck(HtmlInMarkdownCheck.ERROR);
|
||||
}
|
||||
if (content.has("matchetype")) {
|
||||
val.setMatchetypeStatus(MatchetypeStatus.Required);
|
||||
}
|
||||
List<String> suppress = new ArrayList<>();
|
||||
if (content.has("suppress")) {
|
||||
for (JsonElement c : content.getAsJsonArray("suppress")) {
|
||||
|
@ -43,6 +43,7 @@
|
||||
"http://hl7.org/fhir/test/CodeSystem/imaginary|null" : null,
|
||||
"http://loinc.org|2.74" : null,
|
||||
"http://example.org/fhir/us/spl/CodeSystem/codesystem-organizationTypes|null" : null,
|
||||
"http://hl7.org/fhir/test/CodeSystem/big|null" : null,
|
||||
"Location|null" : null,
|
||||
"http://terminology.hl7.org/CodeSystem/v3-NullFlavor|2018-08-12" : null,
|
||||
"http://loinc.org|current" : null,
|
||||
|
@ -8,6 +8,7 @@
|
||||
"http://hl7.org/fhir/us/qicore/ValueSet/qicore-negation-reason" : null,
|
||||
"http://fhir.ch/ig/ch-ig/ValueSet/OrganizationType" : null,
|
||||
"https://fhir.kbv.de/ValueSet/KBV_VS_SFHIR_ICD_SEITENLOKALISATION" : null,
|
||||
"http://hl7.org/fhir/test/CodeSystem/big|null" : null,
|
||||
"http://fhir.abda.de/eRezeptAbgabedaten/ValueSet/DAV-VS-ERP-DEUEV-Anlage-8" : null,
|
||||
"http://loinc.org/vs/LL378-1" : null,
|
||||
"http://something/something|null" : null,
|
||||
|
2
pom.xml
2
pom.xml
@ -23,7 +23,7 @@
|
||||
<commons_io_version>2.17.0</commons_io_version>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.7.6</validator_test_case_version>
|
||||
<validator_test_case_version>1.7.7-SNAPSHOT</validator_test_case_version>
|
||||
<jackson_version>2.17.0</jackson_version>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
Loading…
x
Reference in New Issue
Block a user