Search in sources :

Example 61 with Rule

use of org.hl7.fhir.utilities.xml.SchematronWriter.Rule in project org.hl7.fhir.core by hapifhir.

the class StructureDefinitionValidator method validateElementDefinition.

private void validateElementDefinition(List<ValidationMessage> errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) {
    boolean typeMustSupport = false;
    List<Element> types = element.getChildrenByName("type");
    Set<String> typeCodes = new HashSet<>();
    for (Element type : types) {
        if (hasMustSupportExtension(type)) {
            typeMustSupport = true;
        }
        String tc = type.getChildValue("code");
        if (type.hasExtension(ToolingExtensions.EXT_FHIR_TYPE)) {
            tc = type.getExtensionValue(ToolingExtensions.EXT_FHIR_TYPE).primitiveValue();
        }
        if (Utilities.noString(tc) && type.hasChild("code")) {
            if (type.getNamedChild("code").hasExtension("http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type")) {
                tc = "*";
            }
        }
        typeCodes.add(tc);
        // check the stated profile - must be a constraint on the type
        if (snapshot || sd != null) {
            validateElementType(errors, type, stack.push(type, -1, null, null), sd, element.getChildValue("path"));
        }
    }
    if (typeMustSupport) {
        if (snapshot) {
            rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, element.getNamedChildValue("path"));
        } else {
            hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path"));
        }
    }
    if (element.hasChild("binding")) {
        Element binding = element.getNamedChild("binding");
        validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, element.getNamedChildValue("path"));
    } else {
    // this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back
    // String bt = boundType(typeCodes);
    // hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt);
    }
    // in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type
    if (snapshot && (element.getIdBase() != null) && (element.getIdBase().contains("."))) {
        if (rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference"), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) {
            // if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint
            boolean repeating = !Utilities.existsInList(element.getChildValue("max"), "0", "1");
            Element v = element.getNamedChild("defaultValue");
            if (v != null) {
                rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes);
            }
            v = element.getNamedChild("fixed");
            if (v != null) {
                rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes);
                hint(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed");
                if (isPrimitiveType(v.fhirType())) {
                    warning(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "fixed");
                }
            }
            v = element.getNamedChild("pattern");
            if (v != null) {
                rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes);
                hint(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "pattern");
                if (isPrimitiveType(v.fhirType())) {
                    warning(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "pattern");
                }
            }
        }
    // if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint
    }
}
Also used : Element(org.hl7.fhir.r5.elementmodel.Element) HashSet(java.util.HashSet)

Example 62 with Rule

use of org.hl7.fhir.utilities.xml.SchematronWriter.Rule in project org.hl7.fhir.core by hapifhir.

the class StructureDefinitionValidator method validateTargetProfile.

private void validateTargetProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path) {
    String p = profile.primitiveValue();
    StructureDefinition sd = context.fetchResource(StructureDefinition.class, p);
    if (code.equals("Reference") || code.equals("CodeableReference")) {
        if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
            StructureDefinition t = determineBaseType(sd);
            if (t == null) {
                rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
            } else {
                rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd.getKind() == StructureDefinitionKind.RESOURCE, I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Resource");
            }
        }
    } else if (code.equals("canonical")) {
        if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
            StructureDefinition t = determineBaseType(sd);
            if (t == null) {
                rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
            } else if (!VersionUtilities.isR5Ver(context.getVersion())) {
                rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t.getType()) || "Resource".equals(t.getType()), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Canonical Resource");
            } else {
                rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t.getType()), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Canonical Resource");
            }
        }
    } else {
        rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_NO_TARGET_PROFILE, code);
    }
}
Also used : StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition)

Example 63 with Rule

use of org.hl7.fhir.utilities.xml.SchematronWriter.Rule in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method validateContains.

private void validateContains(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, ElementDefinition child, ElementDefinition context, Element resource, Element element, NodeStack stack, IdStatus idstatus, StructureDefinition parentProfile) throws FHIRException {
    SpecialElement special = element.getSpecial();
    ContainedReferenceValidationPolicy containedValidationPolicy = getPolicyAdvisor() == null ? ContainedReferenceValidationPolicy.CHECK_VALID : getPolicyAdvisor().policyForContained(this, hostContext, context.fhirType(), context.getId(), special, path, parentProfile.getUrl());
    if (containedValidationPolicy.ignore()) {
        return;
    }
    String resourceName = element.getType();
    TypeRefComponent typeForResource = null;
    CommaSeparatedStringBuilder bt = new CommaSeparatedStringBuilder();
    // Iterate through all possible types
    for (TypeRefComponent type : child.getType()) {
        bt.append(type.getCode());
        if (type.getCode().equals("Resource") || type.getCode().equals(resourceName)) {
            typeForResource = type;
            break;
        }
    }
    stack.qualifyPath(".ofType(" + resourceName + ")");
    if (typeForResource == null) {
        rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName, bt.toString());
    } else if (isValidResourceType(resourceName, typeForResource)) {
        if (containedValidationPolicy.checkValid()) {
            // special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise
            ValidatorHostContext hc = null;
            if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
                resource = element;
                assert Utilities.existsInList(hostContext.getRootResource().fhirType(), "Bundle", "Parameters") : "Resource is " + hostContext.getRootResource().fhirType() + ", expected Bundle or Parameters";
                // root becomes the grouping resource (should be either bundle or parameters)
                hc = hostContext.forEntry(element, hostContext.getRootResource());
            } else {
                hc = hostContext.forContained(element);
            }
            stack.resetIds();
            if (special != null) {
                switch(special) {
                    case BUNDLE_ENTRY:
                    case BUNDLE_OUTCOME:
                    case PARAMETER:
                        idstatus = IdStatus.OPTIONAL;
                        break;
                    case CONTAINED:
                        stack.setContained(true);
                        idstatus = IdStatus.REQUIRED;
                        break;
                    default:
                        break;
                }
            }
            if (typeForResource.getProfile().size() == 1) {
                long t = System.nanoTime();
                StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, typeForResource.getProfile().get(0).asStringValue());
                timeTracker.sd(t);
                trackUsage(profile, hostContext, element);
                if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) {
                    validateResource(hc, errors, resource, element, profile, idstatus, stack);
                }
            } else if (typeForResource.getProfile().isEmpty()) {
                long t = System.nanoTime();
                StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + resourceName);
                timeTracker.sd(t);
                trackUsage(profile, hostContext, element);
                if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), resourceName)) {
                    validateResource(hc, errors, resource, element, profile, idstatus, stack);
                }
            } else {
                CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
                for (CanonicalType u : typeForResource.getProfile()) {
                    b.append(u.asStringValue());
                }
                rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, special.toHuman(), typeForResource.getCode(), b.toString());
            }
        }
    } else {
        List<String> types = new ArrayList<>();
        for (UriType u : typeForResource.getProfile()) {
            StructureDefinition sd = this.context.fetchResource(StructureDefinition.class, u.getValue());
            if (sd != null && !types.contains(sd.getType())) {
                types.add(sd.getType());
            }
        }
        if (types.size() == 1) {
            rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE2, resourceName, types.get(0));
        } else {
            rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE3, resourceName, types);
        }
    }
}
Also used : StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ValidatorHostContext(org.hl7.fhir.validation.instance.utils.ValidatorHostContext) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) CommaSeparatedStringBuilder(org.hl7.fhir.utilities.CommaSeparatedStringBuilder) ArrayList(java.util.ArrayList) List(java.util.List) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) UriType(org.hl7.fhir.r5.model.UriType)

Example 64 with Rule

use of org.hl7.fhir.utilities.xml.SchematronWriter.Rule in project org.hl7.fhir.core by hapifhir.

the class CodeSystemValidator method metaChecks.

private void metaChecks(List<ValidationMessage> errors, Element cs, NodeStack stack, String url, String content, String caseSensitive, String hierarchyMeaning, boolean isSupplement) {
    if (isSupplement) {
        if (!"supplement".equals(content)) {
            NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null);
            rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG);
        }
        if (!Utilities.noString(caseSensitive)) {
            NodeStack s = stack.push(cs.getNamedChild("caseSensitive"), -1, null, null);
            rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive");
        }
        if (!Utilities.noString(hierarchyMeaning)) {
            NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning"), -1, null, null);
            rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive");
        }
    } else {
        boolean isHL7 = url != null && (url.contains("hl7.org") || url.contains("fhir.org"));
        if (Utilities.noString(content)) {
            NodeStack s = stack;
            Element c = cs.getNamedChild("content");
            if (c != null) {
                s = stack.push(c, -1, null, null);
            }
            if (isHL7) {
                rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHALL, "content");
            } else {
                warning(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "content");
            }
        } else if ("supplement".equals(content)) {
            NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null);
            rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING);
        }
        if (Utilities.noString(caseSensitive)) {
            NodeStack s = stack;
            Element c = cs.getNamedChild("caseSensitive");
            if (c != null) {
                s = stack.push(c, -1, null, null);
            }
            if (isHL7) {
                warning(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD, "caseSensitive");
            } else {
                hint(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "caseSensitive");
            }
        }
        if (Utilities.noString(hierarchyMeaning) && hasHeirarchy(cs)) {
            NodeStack s = stack;
            Element c = cs.getNamedChild("hierarchyMeaning");
            if (c != null) {
                s = stack.push(c, -1, null, null);
            }
            if (isHL7) {
                warning(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD, "hierarchyMeaning");
            } else {
                hint(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "hierarchyMeaning");
            }
        }
    }
}
Also used : Element(org.hl7.fhir.r5.elementmodel.Element) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack)

Example 65 with Rule

use of org.hl7.fhir.utilities.xml.SchematronWriter.Rule in project org.hl7.fhir.core by hapifhir.

the class MeasureValidator method validateMeasureCriteria.

private void validateMeasureCriteria(ValidatorHostContext hostContext, List<ValidationMessage> errors, MeasureContext mctxt, Element crit, NodeStack nsc) {
    String mimeType = crit.getChildValue("language");
    if (!Utilities.noString(mimeType)) {
        // that would be an error elsewhere
        if ("text/cql".equals(mimeType) || "text/cql.identifier".equals(mimeType)) {
            String cqlRef = crit.getChildValue("expression");
            Library lib = null;
            if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), mctxt.libraries().size() > 0, I18nConstants.MEASURE_M_CRITERIA_CQL_NO_LIB)) {
                if (cqlRef.contains(".")) {
                    String name = cqlRef.substring(0, cqlRef.indexOf("."));
                    cqlRef = cqlRef.substring(cqlRef.indexOf(".") + 1);
                    for (Library l : mctxt.libraries()) {
                        if (name.equals(l.getName())) {
                            if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), lib == null, I18nConstants.MEASURE_M_CRITERIA_CQL_LIB_DUPL)) {
                                lib = l;
                            }
                        }
                    }
                    rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), lib != null, I18nConstants.MEASURE_M_CRITERIA_CQL_LIB_NOT_FOUND, name);
                } else {
                    if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), mctxt.libraries().size() == 1, I18nConstants.MEASURE_M_CRITERIA_CQL_ONLY_ONE_LIB)) {
                        lib = mctxt.libraries().get(0);
                    }
                }
            }
            if (lib != null) {
                if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), lib.hasUserData(MeasureContext.USER_DATA_ELM), I18nConstants.MEASURE_M_CRITERIA_CQL_NO_ELM, lib.getUrl())) {
                    if (lib.getUserData(MeasureContext.USER_DATA_ELM) instanceof String) {
                        rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), false, I18nConstants.MEASURE_M_CRITERIA_CQL_ERROR, lib.getUrl(), lib.getUserString(MeasureContext.USER_DATA_ELM));
                    } else if (lib.getUserData(MeasureContext.USER_DATA_ELM) instanceof Document) {
                        org.w3c.dom.Element elm = ((Document) lib.getUserData(MeasureContext.USER_DATA_ELM)).getDocumentElement();
                        if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), isValidElm(elm), I18nConstants.MEASURE_M_CRITERIA_CQL_ELM_NOT_VALID, lib.getUrl(), cqlRef)) {
                            rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), hasCqlTarget(elm, cqlRef), I18nConstants.MEASURE_M_CRITERIA_CQL_NOT_FOUND, lib.getUrl(), cqlRef);
                        }
                    }
                }
            }
        } else if ("text/fhirpath".equals(mimeType)) {
            warning(errors, IssueType.REQUIRED, crit.line(), crit.col(), nsc.getLiteralPath(), false, I18nConstants.MEASURE_M_CRITERIA_UNKNOWN, mimeType);
        } else if ("application/x-fhir-query".equals(mimeType)) {
            warning(errors, IssueType.REQUIRED, crit.line(), crit.col(), nsc.getLiteralPath(), false, I18nConstants.MEASURE_M_CRITERIA_UNKNOWN, mimeType);
        } else {
            warning(errors, IssueType.REQUIRED, crit.line(), crit.col(), nsc.getLiteralPath(), false, I18nConstants.MEASURE_M_CRITERIA_UNKNOWN, mimeType);
        }
    }
}
Also used : Element(org.hl7.fhir.r5.elementmodel.Element) Library(org.hl7.fhir.r5.model.Library) Document(org.w3c.dom.Document)

Aggregations

FHIRException (org.hl7.fhir.exceptions.FHIRException)76 ArrayList (java.util.ArrayList)46 Element (org.hl7.fhir.r5.elementmodel.Element)38 IOException (java.io.IOException)28 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)26 NodeStack (org.hl7.fhir.validation.instance.utils.NodeStack)23 PathEngineException (org.hl7.fhir.exceptions.PathEngineException)20 StructureDefinition (org.hl7.fhir.r5.model.StructureDefinition)20 ValidationMessage (org.hl7.fhir.utilities.validation.ValidationMessage)19 IndexedElement (org.hl7.fhir.validation.instance.utils.IndexedElement)17 NotImplementedException (org.apache.commons.lang3.NotImplementedException)16 FHIRFormatError (org.hl7.fhir.exceptions.FHIRFormatError)14 FHIRLexerException (org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException)14 Complex (org.hl7.fhir.dstu3.utils.formats.Turtle.Complex)13 TerminologyServiceException (org.hl7.fhir.exceptions.TerminologyServiceException)13 NamedElement (org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement)13 ContactPoint (org.hl7.fhir.r5.model.ContactPoint)13 ValueSet (org.hl7.fhir.r5.model.ValueSet)13 XhtmlNode (org.hl7.fhir.utilities.xhtml.XhtmlNode)13 SpecialElement (org.hl7.fhir.r5.elementmodel.Element.SpecialElement)12