diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a2a7149e8..e1f659890 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -3,3 +3,4 @@ * add procedures conversion form dstu2 to r4 * add medication conversion from dstu2 to r4 * Adding Maven exec to test validation cli jar +* Validation of cardinality on address-line elements containing pattern elements fixed diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SIDUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SIDUtilities.java new file mode 100644 index 000000000..69664a879 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SIDUtilities.java @@ -0,0 +1,62 @@ +package org.hl7.fhir.utilities; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class SIDUtilities { + + public static List codeSystemList() { + List codeSystems = new ArrayList<>(); + codeSystems.add("http://hl7.org/fhir/sid/ndc"); + codeSystems.add("http://hl7.org/fhir/sid/icd-10"); + codeSystems.add("http://hl7.org/fhir/sid/icpc2"); + codeSystems.add("http://hl7.org/fhir/sid/icd-9"); + codeSystems.add("http://hl7.org/fhir/sid/icd-10"); + codeSystems.add("http://hl7.org/fhir/sid/icpc2"); + codeSystems.add("http://hl7.org/fhir/sid/cvx"); + codeSystems.add("http://hl7.org/fhir/sid/srt"); + codeSystems.add("http://hl7.org/fhir/sid/icd-10-vn"); + codeSystems.add("http://hl7.org/fhir/sid/icd-10-cm"); + codeSystems.add("http://hl7.org/fhir/sid/icd-9-cm"); + return codeSystems; + } + + public static List idSystemList() { + List idSystems = new ArrayList<>(); + idSystems.add("http://hl7.org/fhir/sid/us-ssn"); + idSystems.add("http://hl7.org/fhir/sid/us-npi"); + idSystems.add("http://hl7.org/fhir/sid/eui-48/bluetooth"); + idSystems.add("http://hl7.org/fhir/sid/eui-48/ethernet"); + return idSystems; + } + + private static boolean isPassPortSID(String url) { + // TODO: verify ISO countrycode part vs country code list + return url.matches("^http:\\/\\/hl7.org\\/fhir\\/sid\\/passport-[a-zA-Z]{3}$"); + } + + public static boolean isknownCodeSystem(String system) { + return codeSystemList().contains(system); + } + + public static boolean isKnownSID(String url) { + return isknownCodeSystem(url) || isknownIDSystem(url); + } + + private static boolean isknownIDSystem(String url) { + return idSystemList().contains(url) || isPassPortSID(url); + } + + public static List allSystemsList() { + List allSystems = new ArrayList<>(); + allSystems.addAll(codeSystemList()); + allSystems.addAll(idSystemList()); + return allSystems; + } + + + + +} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index 93e0220f2..2fdd04965 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -274,6 +274,7 @@ public class I18nConstants { public static final String OBJECT_MUST_HAVE_SOME_CONTENT = "Object_must_have_some_content"; public static final String PACKAGE_VERSION_MISMATCH = "PACKAGE_VERSION_MISMATCH"; public static final String PARSER_TYPE__NOT_SUPPORTED = "Parser_Type__not_supported"; + public static final String PATTERN_CHECK_STRING = "PATTERN_CHECK_STRING"; public static final String PROBLEM_EVALUATING_SLICING_EXPRESSION_FOR_ELEMENT_IN_PROFILE__PATH__FHIRPATH___ = "Problem_evaluating_slicing_expression_for_element_in_profile__path__fhirPath___"; public static final String PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__ = "Problem_processing_expression__in_profile__path__"; public static final String PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE_WITH_A_PROFILE__IN_PROFILE_ = "Profile_based_discriminators_must_have_a_type_with_a_profile__in_profile_"; diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index adf551e39..50276b3da 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -653,3 +653,4 @@ BUNDLE_SEARCH_ENTRY_WRONG_RESOURCE_TYPE_OUTCOME = This is not an OperationOutcom BUNDLE_SEARCH_ENTRY_WRONG_RESOURCE_TYPE_NO_MODE = This is not a matching resource type for the specified search (is a search mode needed?) ({0} expecting {1}) BUNDLE_SEARCH_NO_MODE = SearchSet bundles should have search modes on the entries INV_FAILED = Rule {0} Failed +PATTERN_CHECK_STRING = The pattern [{0}] defined in the profile {1} not found. Issues: {2} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index c0bec1f31..a56fb03bc 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -728,9 +728,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } if (context.fetchResource(Resource.class, url) != null) return true; - if (Utilities.existsInList(url, "http://hl7.org/fhir/sid/us-ssn", "http://hl7.org/fhir/sid/cvx", "http://hl7.org/fhir/sid/ndc", "http://hl7.org/fhir/sid/us-npi", "http://hl7.org/fhir/sid/icd-10", - "http://hl7.org/fhir/sid/icd-10-vn", "http://hl7.org/fhir/sid/icd-10-cm", "http://hl7.org/fhir/sid/icd-9-cm", "http://hl7.org/fhir/w5", "http://hl7.org/fhir/fivews", - "http://hl7.org/fhir/workflow", "http://hl7.org/fhir/ConsentPolicy/opt-out", "http://hl7.org/fhir/ConsentPolicy/opt-in")) { + if (SIDUtilities.isKnownSID(url) || + Utilities.existsInList(url, "http://hl7.org/fhir/w5", "http://hl7.org/fhir/fivews", "http://hl7.org/fhir/workflow", "http://hl7.org/fhir/ConsentPolicy/opt-out", "http://hl7.org/fhir/ConsentPolicy/opt-in")) { return true; } if (Utilities.existsInList(url, "http://loinc.org", "http://unitsofmeasure.org", "http://snomed.info/sct")) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index b96fad244..119cd9afd 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -134,6 +134,7 @@ import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.SIDUtilities; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities.DecimalStatus; import org.hl7.fhir.utilities.VersionUtilities; @@ -762,10 +763,40 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat List lines = new ArrayList(); focus.getNamedChildren("line", lines); - if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, lines.size() == fixed.getLine().size(), I18nConstants.FIXED_TYPE_CHECKS_DT_ADDRESS_LINE, Integer.toString(fixed.getLine().size()), Integer.toString(lines.size()))) { - for (int i = 0; i < lines.size(); i++) - checkFixedValue(errors, path + ".coding", lines.get(i), fixed.getLine().get(i), fixedSource, "coding", focus, pattern); - } + boolean lineSizeCheck; + + if (pattern) { + lineSizeCheck = lines.size() >= fixed.getLine().size(); + if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, lineSizeCheck, I18nConstants.FIXED_TYPE_CHECKS_DT_ADDRESS_LINE, Integer.toString(fixed.getLine().size()), + Integer.toString(lines.size()))) { + for (int i = 0; i < fixed.getLine().size(); i++) { + StringType fixedLine = fixed.getLine().get(i); + boolean found = false; + List allErrorsFixed = new ArrayList<>(); + List errorsFixed = null; + for (int j = 0; j < lines.size() && !found; ++j) { + errorsFixed = new ArrayList<>(); + checkFixedValue(errorsFixed, path + ".line", lines.get(j), fixedLine, fixedSource, "line", focus, pattern); + if (!hasErrors(errorsFixed)) { + found = true; + } else { + errorsFixed.stream().filter(t -> t.getLevel().ordinal() >= IssueSeverity.ERROR.ordinal()).forEach(t -> allErrorsFixed.add(t)); + } + } + if (!found) { + rule(errorsFixed, IssueType.VALUE, focus.line(), focus.col(), path, false, I18nConstants.PATTERN_CHECK_STRING, fixedLine.getValue(), fixedSource, allErrorsFixed); + } + } + } + } else if (!pattern) { + lineSizeCheck = lines.size() == fixed.getLine().size(); + if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, lineSizeCheck, I18nConstants.FIXED_TYPE_CHECKS_DT_ADDRESS_LINE, + Integer.toString(fixed.getLine().size()), Integer.toString(lines.size()))) { + for (int i = 0; i < lines.size(); i++) { + checkFixedValue(errors, path + ".line", lines.get(i), fixed.getLine().get(i), fixedSource, "line", focus, pattern); + } + } + } } private void checkAttachment(List errors, String path, Element focus, Attachment fixed, String fixedSource, boolean pattern) { @@ -807,8 +838,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_WRONG_BUILD, system, suggestSystemForBuild(system)); return false; } else if (system.startsWith("http://hl7.org/fhir") || system.startsWith("https://hl7.org/fhir") || system.startsWith("http://www.hl7.org/fhir") || system.startsWith("https://www.hl7.org/fhir")) { - if (Utilities.existsInList(system, "http://hl7.org/fhir/sid/icd-10", "http://hl7.org/fhir/sid/cvx", "http://hl7.org/fhir/sid/icd-10", "http://hl7.org/fhir/sid/icd-10-cm", - "http://hl7.org/fhir/sid/icd-9-cm", "http://hl7.org/fhir/sid/icd-9", "http://hl7.org/fhir/sid/ndc", "http://hl7.org/fhir/sid/srt")) { + if (SIDUtilities.isknownCodeSystem(system)) { return true; // else don't check these (for now) } else if (system.startsWith("http://hl7.org/fhir/test")) { return true; // we don't validate these