Search in sources :

Example 6 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method checkMustSupport.

public void checkMustSupport(StructureDefinition profile, ElementInfo ei) {
    String usesMustSupport = profile.getUserString("usesMustSupport");
    if (usesMustSupport == null) {
        usesMustSupport = "N";
        for (ElementDefinition pe : profile.getSnapshot().getElement()) {
            if (pe.getMustSupport()) {
                usesMustSupport = "Y";
                break;
            }
        }
        profile.setUserData("usesMustSupport", usesMustSupport);
    }
    if (usesMustSupport.equals("Y")) {
        String elementSupported = ei.getElement().getUserString("elementSupported");
        if (elementSupported == null || ei.definition.getMustSupport())
            if (ei.definition.getMustSupport()) {
                ei.getElement().setUserData("elementSupported", "Y");
            }
    }
}
Also used : TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition)

Example 7 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method listChildren.

public List<ElementInfo> listChildren(Element element, NodeStack stack) {
    // 1. List the children, and remember their exact path (convenience)
    List<ElementInfo> children = new ArrayList<ElementInfo>();
    ChildIterator iter = new ChildIterator(this, stack.getLiteralPath(), element);
    while (iter.next()) children.add(new ElementInfo(iter.name(), iter.element(), iter.path(), iter.count()));
    return children;
}
Also used : ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) ArrayList(java.util.ArrayList) ChildIterator(org.hl7.fhir.validation.instance.utils.ChildIterator)

Example 8 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method assignChildren.

public List<String> assignChildren(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, Element resource, NodeStack stack, List<ElementDefinition> childDefinitions, List<ElementInfo> children) throws DefinitionException {
    // 2. assign children to a definition
    // for each definition, for each child, check whether it belongs in the slice
    ElementDefinition slicer = null;
    boolean unsupportedSlicing = false;
    List<String> problematicPaths = new ArrayList<String>();
    String slicingPath = null;
    int sliceOffset = 0;
    for (int i = 0; i < childDefinitions.size(); i++) {
        ElementDefinition ed = childDefinitions.get(i);
        boolean childUnsupportedSlicing = false;
        boolean process = true;
        if (ed.hasSlicing() && !ed.getSlicing().getOrdered()) {
            slicingPath = ed.getPath();
        } else if (slicingPath != null && ed.getPath().equals(slicingPath)) {
            // nothing
            ;
        } else if (slicingPath != null && !ed.getPath().startsWith(slicingPath)) {
            slicingPath = null;
        }
        // where are we with slicing
        if (ed.hasSlicing()) {
            if (slicer != null && slicer.getPath().equals(ed.getPath())) {
                String errorContext = "profile " + profile.getUrl();
                if (!resource.getChildValue(ID).isEmpty()) {
                    errorContext += "; instance " + resource.getChildValue("id");
                }
                throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));
            }
            slicer = ed;
            process = false;
            sliceOffset = i;
        } else if (slicer != null && !slicer.getPath().equals(ed.getPath()))
            slicer = null;
        for (ElementInfo ei : children) {
            if (ei.sliceInfo == null) {
                ei.sliceInfo = new ArrayList<>();
            }
            unsupportedSlicing = matchSlice(hostContext, errors, ei.sliceInfo, profile, stack, slicer, unsupportedSlicing, problematicPaths, sliceOffset, i, ed, childUnsupportedSlicing, ei);
        }
    }
    int last = -1;
    ElementInfo lastei = null;
    int lastSlice = -1;
    for (ElementInfo ei : children) {
        String sliceInfo = "";
        if (slicer != null) {
            sliceInfo = " (slice: " + slicer.getPath() + ")";
        }
        if (!unsupportedSlicing) {
            if (ei.additionalSlice && ei.definition != null) {
                if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPENATEND) && true) /* TODO: replace "true" with condition to check that this element is at "end" */
                {
                    slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.getPath(), false, isProfile(slicer) || isCritical(ei.sliceInfo), context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : " defined in the profile " + profile.getUrl()), context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : I18nConstants.DEFINED_IN_THE_PROFILE + profile.getUrl()) + errorSummaryForSlicingAsHtml(ei.sliceInfo), errorSummaryForSlicingAsText(ei.sliceInfo));
                } else if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.CLOSED)) {
                    rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTSLICE, (profile == null ? "" : " defined in the profile " + profile.getUrl()), errorSummaryForSlicing(ei.sliceInfo));
                }
            } else {
                // Don't raise this if we're in an abstract profile, like Resource
                if (!profile.getAbstract()) {
                    rule(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.getPath(), (ei.definition != null), I18nConstants.VALIDATION_VAL_PROFILE_NOTALLOWED, profile.getUrl());
                }
            }
        }
        // TODO: Should get the order of elements correct when parsing elements that are XML attributes vs. elements
        boolean isXmlAttr = false;
        if (ei.definition != null) {
            for (Enumeration<PropertyRepresentation> r : ei.definition.getRepresentation()) {
                if (r.getValue() == PropertyRepresentation.XMLATTR) {
                    isXmlAttr = true;
                    break;
                }
            }
        }
        if (!ToolingExtensions.readBoolExtension(profile, "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-no-order")) {
            boolean ok = (ei.definition == null) || (ei.index >= last) || isXmlAttr;
            rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), ok, I18nConstants.VALIDATION_VAL_PROFILE_OUTOFORDER, profile.getUrl(), ei.getName(), lastei == null ? "(null)" : lastei.getName());
        }
        if (ei.slice != null && ei.index == last && ei.slice.getSlicing().getOrdered()) {
            rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), (ei.definition == null) || (ei.sliceindex >= lastSlice) || isXmlAttr, I18nConstants.VALIDATION_VAL_PROFILE_SLICEORDER, profile.getUrl(), ei.getName());
        }
        if (ei.definition == null || !isXmlAttr) {
            last = ei.index;
            lastei = ei;
        }
        if (ei.slice != null) {
            lastSlice = ei.sliceindex;
        } else {
            lastSlice = -1;
        }
    }
    return problematicPaths;
}
Also used : PropertyRepresentation(org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation) ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) ArrayList(java.util.ArrayList) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition) DefinitionException(org.hl7.fhir.exceptions.DefinitionException) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Example 9 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method validateElement.

private void validateElement(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, StructureDefinition cprofile, ElementDefinition context, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, String extensionUrl) throws FHIRException {
    String id = element.getChildValue("id");
    if (!Utilities.noString(id)) {
        if (stack.getIds().containsKey(id) && stack.getIds().get(id) != element) {
            rule(errors, IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.DUPLICATE_ID, id);
        }
        if (!stack.isResetPoint()) {
            stack.getIds().put(id, element);
        }
    }
    if (definition.getPath().equals("StructureDefinition.snapshot")) {
        // work around a known issue in the spec, that ids are duplicated in snapshot and differential
        stack.resetIds();
    }
    // check type invariants
    checkInvariants(hostContext, errors, profile, definition, resource, element, stack, false);
    if (definition.getFixed() != null) {
        checkFixedValue(errors, stack.getLiteralPath(), element, definition.getFixed(), profile.getUrl(), definition.getSliceName(), null, false);
    }
    if (definition.getPattern() != null) {
        checkFixedValue(errors, stack.getLiteralPath(), element, definition.getPattern(), profile.getUrl(), definition.getSliceName(), null, true);
    }
    // get the list of direct defined children, including slices
    List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(profile, definition);
    if (childDefinitions.isEmpty()) {
        if (actualType == null)
            // there'll be an error elsewhere in this case, and we're going to stop.
            return;
        childDefinitions = getActualTypeChildren(hostContext, element, actualType);
    } else if (definition.getType().size() > 1) {
        // this only happens when the profile constrains the abstract children but leaves th choice open.
        if (actualType == null)
            // there'll be an error elsewhere in this case, and we're going to stop.
            return;
        List<ElementDefinition> typeChildDefinitions = getActualTypeChildren(hostContext, element, actualType);
        // what were going to do is merge them - the type is not allowed to constrain things that the child definitions already do (well, if it does, it'll be ignored)
        mergeChildLists(childDefinitions, typeChildDefinitions, definition.getPath(), actualType);
    }
    List<ElementInfo> children = listChildren(element, stack);
    List<String> problematicPaths = assignChildren(hostContext, errors, profile, resource, stack, childDefinitions, children);
    checkCardinalities(errors, profile, element, stack, childDefinitions, children, problematicPaths);
    // 5. inspect each child for validity
    for (ElementInfo ei : children) {
        checkChild(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl);
    }
}
Also used : ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) ArrayList(java.util.ArrayList) List(java.util.List) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition)

Example 10 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method checkCardinalities.

public void checkCardinalities(List<ValidationMessage> errors, StructureDefinition profile, Element element, NodeStack stack, List<ElementDefinition> childDefinitions, List<ElementInfo> children, List<String> problematicPaths) throws DefinitionException {
    // 3. report any definitions that have a cardinality problem
    for (ElementDefinition ed : childDefinitions) {
        if (ed.getRepresentation().isEmpty()) {
            // ignore xml attributes
            int count = 0;
            List<ElementDefinition> slices = null;
            if (ed.hasSlicing())
                slices = profileUtilities.getSliceList(profile, ed);
            for (ElementInfo ei : children) if (ei.definition == ed)
                count++;
            else if (slices != null) {
                for (ElementDefinition sed : slices) {
                    if (ei.definition == sed) {
                        count++;
                        break;
                    }
                }
            }
            if (ed.getMin() > 0) {
                if (problematicPaths.contains(ed.getPath()))
                    hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMIN, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()));
                else {
                    if (count < ed.getMin()) {
                        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
                    }
                }
            }
            if (ed.hasMax() && !ed.getMax().equals("*")) {
                if (problematicPaths.contains(ed.getPath()))
                    hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count <= Integer.parseInt(ed.getMax()), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMAX, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), ed.getMax());
                else if (count > Integer.parseInt(ed.getMax())) {
                    rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MAXIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), ed.getMax(), Integer.toString(count));
                }
            }
        }
    }
}
Also used : ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Aggregations

ElementDefinition (org.hl7.fhir.r5.model.ElementDefinition)5 TypedElementDefinition (org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition)5 ArrayList (java.util.ArrayList)4 ElementInfo (org.hl7.fhir.validation.instance.utils.ElementInfo)4 ContactPoint (org.hl7.fhir.r5.model.ContactPoint)3 List (java.util.List)2 ElementDefn (org.hl7.fhir.definitions.model.ElementDefn)2 Element (org.hl7.fhir.r5.elementmodel.Element)2 SpecialElement (org.hl7.fhir.r5.elementmodel.Element.SpecialElement)2 NamedElement (org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement)2 IndexedElement (org.hl7.fhir.validation.instance.utils.IndexedElement)2 JsonElement (com.google.gson.JsonElement)1 JsonObject (com.google.gson.JsonObject)1 File (java.io.File)1 HashMap (java.util.HashMap)1 ResourceDefn (org.hl7.fhir.definitions.model.ResourceDefn)1 TypeRef (org.hl7.fhir.definitions.model.TypeRef)1 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)1 CanonicalType (org.hl7.fhir.r5.model.CanonicalType)1 PropertyRepresentation (org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation)1