Search in sources :

Example 1 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project kindling by HL7.

the class XVerPathsGenerator method process.

private void process(ElementDefn ed, String path) {
    ElementInfo ei = new ElementInfo();
    ei.path = path;
    r5List.add(ei);
    ElementInfo r4 = r4List.get(path);
    if (ed.getTypes().size() > 0) {
        // leaf
        for (TypeRef tr : ed.getTypes()) {
            if (r4 == null || !r4.types.contains(tr.summary())) {
                ei.types.add(tr.summary());
            }
        }
    } else {
        for (ElementDefn child : ed.getElements()) {
            if (r4 == null || !r4.elements.contains(child.getName())) {
                ei.elements.add(child.getName());
            }
            process(child, path + "." + child.getName());
        }
    }
}
Also used : TypeRef(org.hl7.fhir.definitions.model.TypeRef) ElementDefn(org.hl7.fhir.definitions.model.ElementDefn)

Example 2 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project kindling by HL7.

the class XVerPathsGenerator method loadR4.

private void loadR4() throws IOException {
    JsonObject r4 = JsonTrackingParser.parseJson(new File(r4Source));
    for (Entry<String, JsonElement> e : r4.entrySet()) {
        JsonObject eo = (JsonObject) e.getValue();
        ElementInfo ei = new ElementInfo();
        if (eo.has("types")) {
            for (JsonElement s : eo.getAsJsonArray("types")) {
                ei.types.add(s.getAsString());
            }
        }
        if (eo.has("elements")) {
            for (JsonElement s : eo.getAsJsonArray("elements")) {
                ei.elements.add(s.getAsString());
            }
        }
        if (!ei.elements.isEmpty() || !ei.types.isEmpty()) {
            r4List.put(e.getKey(), ei);
        }
    }
}
Also used : JsonElement(com.google.gson.JsonElement) JsonObject(com.google.gson.JsonObject) File(java.io.File) TextFile(org.hl7.fhir.utilities.TextFile)

Example 3 with ElementInfo

use of org.hl7.fhir.validation.instance.utils.ElementInfo in project kindling by HL7.

the class XVerPathsGenerator method execute.

public void execute() throws IOException {
    // load the R4 content; can't be an extension if it already matches R4
    loadR4();
    // iterate all the elements, building a list
    for (String s : sorted(definitions.getTypes().keySet())) {
        ElementDefn ed = definitions.getTypes().get(s);
        process(ed);
    }
    for (String s : sorted(definitions.getBaseResources().keySet())) {
        ResourceDefn ed = definitions.getBaseResources().get(s);
        process(ed.getRoot());
    }
    for (String s : sorted(definitions.getResources().keySet())) {
        ResourceDefn ed = definitions.getResources().get(s);
        process(ed.getRoot());
    }
    StringBuilder r5 = new StringBuilder();
    r5.append("{\r\n");
    int i = 0;
    for (ElementInfo ei : r5List) {
        r5.append(" \"" + ei.path + "\": { ");
        if (ei.types.size() > 0) {
            r5.append("\"types\": [");
            boolean first = true;
            for (String s : ei.types) {
                if (first)
                    first = false;
                else
                    r5.append(", ");
                r5.append("\"" + s + "\"");
            }
            r5.append("]");
        } else if (ei.elements.size() > 0) {
            r5.append("\"elements\": [");
            boolean first = true;
            for (String s : ei.elements) {
                if (first)
                    first = false;
                else
                    r5.append(", ");
                r5.append("\"" + s + "\"");
            }
            r5.append("]");
        }
        i++;
        if (i == r5List.size()) {
            r5.append(" }\r\n");
        } else {
            r5.append(" },\r\n");
        }
    }
    r5.append("}\r\n");
    TextFile.stringToFile(r5.toString(), dest);
}
Also used : ElementDefn(org.hl7.fhir.definitions.model.ElementDefn) ResourceDefn(org.hl7.fhir.definitions.model.ResourceDefn)

Example 4 with ElementInfo

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

the class InstanceValidator method idStatusForEntry.

private IdStatus idStatusForEntry(Element ep, ElementInfo ei) {
    if (isBundleEntry(ei.getPath())) {
        Element req = ep.getNamedChild("request");
        Element resp = ep.getNamedChild("response");
        Element fullUrl = ep.getNamedChild(FULL_URL);
        Element method = null;
        Element url = null;
        if (req != null) {
            method = req.getNamedChild("method");
            url = req.getNamedChild("url");
        }
        if (resp != null) {
            return IdStatus.OPTIONAL;
        }
        if (method == null) {
            if (fullUrl == null)
                return IdStatus.REQUIRED;
            else if (fullUrl.primitiveValue().startsWith("urn:uuid:") || fullUrl.primitiveValue().startsWith("urn:oid:"))
                return IdStatus.OPTIONAL;
            else
                return IdStatus.REQUIRED;
        } else {
            String s = method.primitiveValue();
            if (s.equals("PUT")) {
                if (url == null)
                    return IdStatus.REQUIRED;
                else
                    // or maybe prohibited? not clear
                    return IdStatus.OPTIONAL;
            } else if (s.equals("POST"))
                // this should be prohibited, but see task 9102
                return IdStatus.OPTIONAL;
            else
                // actually, we should never get to here; a bundle entry with method get/delete should not have a resource
                return IdStatus.OPTIONAL;
        }
    } else if (isParametersEntry(ei.getPath()) || isBundleOutcome(ei.getPath()))
        return IdStatus.OPTIONAL;
    else
        return IdStatus.REQUIRED;
}
Also used : NamedElement(org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) Element(org.hl7.fhir.r5.elementmodel.Element)

Example 5 with ElementInfo

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

the class InstanceValidator method checkChildByDefinition.

public void checkChildByDefinition(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl, ElementDefinition checkDefn, boolean isSlice) {
    List<String> profiles = new ArrayList<String>();
    String type = null;
    ElementDefinition typeDefn = null;
    checkMustSupport(profile, ei);
    if (checkDefn.getType().size() == 1 && !"*".equals(checkDefn.getType().get(0).getWorkingCode()) && !"Element".equals(checkDefn.getType().get(0).getWorkingCode()) && !"BackboneElement".equals(checkDefn.getType().get(0).getWorkingCode())) {
        type = checkDefn.getType().get(0).getWorkingCode();
        String stype = ei.getElement().fhirType();
        if (checkDefn.isChoice() && !stype.equals(type)) {
            if ("Extension".equals(profile.getType())) {
            // error will be raised elsewhere
            } else {
                rule(errors, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), false, I18nConstants.EXTENSION_PROF_TYPE, profile.getUrl(), type, stype);
            }
        }
        // Excluding reference is a kludge to get around versioning issues
        if (checkDefn.getType().get(0).hasProfile()) {
            for (CanonicalType p : checkDefn.getType().get(0).getProfile()) {
                profiles.add(p.getValue());
            }
        }
    } else if (checkDefn.getType().size() == 1 && "*".equals(checkDefn.getType().get(0).getWorkingCode())) {
        String prefix = tail(checkDefn.getPath());
        assert prefix.endsWith("[x]");
        type = ei.getName().substring(prefix.length() - 3);
        if (isPrimitiveType(type))
            type = Utilities.uncapitalize(type);
        if (checkDefn.getType().get(0).hasProfile()) {
            for (CanonicalType p : checkDefn.getType().get(0).getProfile()) {
                profiles.add(p.getValue());
            }
        }
    } else if (checkDefn.getType().size() > 1) {
        String prefix = tail(checkDefn.getPath());
        assert typesAreAllReference(checkDefn.getType()) || checkDefn.hasRepresentation(PropertyRepresentation.TYPEATTR) || prefix.endsWith("[x]") || isResourceAndTypes(checkDefn) : "Multiple Types allowed, but name is wrong @ " + checkDefn.getPath() + ": " + checkDefn.typeSummaryVB();
        if (checkDefn.hasRepresentation(PropertyRepresentation.TYPEATTR)) {
            type = ei.getElement().getType();
        } else if (ei.getElement().isResource()) {
            type = ei.getElement().fhirType();
        } else {
            prefix = prefix.substring(0, prefix.length() - 3);
            for (TypeRefComponent t : checkDefn.getType()) if ((prefix + Utilities.capitalize(t.getWorkingCode())).equals(ei.getName())) {
                type = t.getWorkingCode();
                // Excluding reference is a kludge to get around versioning issues
                if (t.hasProfile() && !type.equals("Reference"))
                    profiles.add(t.getProfile().get(0).getValue());
            }
        }
        if (type == null) {
            TypeRefComponent trc = checkDefn.getType().get(0);
            if (trc.getWorkingCode().equals("Reference"))
                type = "Reference";
            else
                rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTYPE, ei.getName(), describeTypes(checkDefn.getType()));
        }
    } else if (checkDefn.getContentReference() != null) {
        typeDefn = resolveNameReference(profile.getSnapshot(), checkDefn.getContentReference());
    } else if (checkDefn.getType().size() == 1 && ("Element".equals(checkDefn.getType().get(0).getWorkingCode()) || "BackboneElement".equals(checkDefn.getType().get(0).getWorkingCode()))) {
        if (checkDefn.getType().get(0).hasProfile()) {
            CanonicalType pu = checkDefn.getType().get(0).getProfile().get(0);
            if (pu.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT))
                profiles.add(pu.getValue() + "#" + pu.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT));
            else
                profiles.add(pu.getValue());
        }
    }
    if (type != null) {
        if (type.startsWith("@")) {
            checkDefn = findElement(profile, type.substring(1));
            if (isSlice) {
                ei.slice = ei.definition;
            } else {
                ei.definition = ei.definition;
            }
            type = null;
        }
    }
    NodeStack localStack = stack.push(ei.getElement(), "*".equals(ei.getDefinition().getBase().getMax()) && ei.count == -1 ? 0 : ei.count, checkDefn, type == null ? typeDefn : resolveType(type, checkDefn.getType()));
    // if (debug) {
    // System.out.println("  check " + localStack.getLiteralPath()+" against "+ei.getDefinition().getId()+" in profile "+profile.getUrl());
    // }
    String localStackLiteralPath = localStack.getLiteralPath();
    String eiPath = ei.getPath();
    if (!eiPath.equals(localStackLiteralPath)) {
        assert (eiPath.equals(localStackLiteralPath)) : "ei.path: " + ei.getPath() + "  -  localStack.getLiteralPath: " + localStackLiteralPath;
    }
    boolean thisIsCodeableConcept = false;
    String thisExtension = null;
    boolean checkDisplay = true;
    SpecialElement special = ei.getElement().getSpecial();
    if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
        checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, ei.getElement(), ei.getElement(), localStack, false);
    } else {
        checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, resource, ei.getElement(), localStack, false);
    }
    ei.getElement().markValidation(profile, checkDefn);
    boolean elementValidated = false;
    if (type != null) {
        if (isPrimitiveType(type)) {
            checkPrimitive(hostContext, errors, ei.getPath(), type, checkDefn, ei.getElement(), profile, stack);
        } else {
            if (checkDefn.hasFixed()) {
                checkFixedValue(errors, ei.getPath(), ei.getElement(), checkDefn.getFixed(), profile.getUrl(), checkDefn.getSliceName(), null, false);
            }
            if (checkDefn.hasPattern()) {
                checkFixedValue(errors, ei.getPath(), ei.getElement(), checkDefn.getPattern(), profile.getUrl(), checkDefn.getSliceName(), null, true);
            }
        }
        if (type.equals("Identifier")) {
            checkIdentifier(errors, ei.getPath(), ei.getElement(), checkDefn);
        } else if (type.equals("Coding")) {
            checkCoding(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack);
        } else if (type.equals("Quantity")) {
            checkQuantity(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack);
        } else if (type.equals("Attachment")) {
            checkAttachment(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack);
        } else if (type.equals("CodeableConcept")) {
            checkDisplay = checkCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack);
            thisIsCodeableConcept = true;
        } else if (type.equals("Reference")) {
            checkReference(hostContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack);
        // We only check extensions if we're not in a complex extension or if the element we're dealing with is not defined as part of that complex extension
        } else if (type.equals("Extension")) {
            Element eurl = ei.getElement().getNamedChild("url");
            if (rule(errors, IssueType.INVALID, ei.getPath(), eurl != null, I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) {
                String url = eurl.primitiveValue();
                thisExtension = url;
                if (rule(errors, IssueType.INVALID, ei.getPath(), !Utilities.noString(url), I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) {
                    if (rule(errors, IssueType.INVALID, ei.getPath(), (extensionUrl != null) || Utilities.isAbsoluteUrl(url), I18nConstants.EXTENSION_EXT_URL_ABSOLUTE)) {
                        checkExtension(hostContext, errors, ei.getPath(), resource, element, ei.getElement(), checkDefn, profile, localStack, stack, extensionUrl);
                    }
                }
            }
        } else if (type.equals("Resource") || isResource(type)) {
            validateContains(hostContext, errors, ei.getPath(), checkDefn, definition, resource, ei.getElement(), localStack, idStatusForEntry(element, ei), // if
            profile);
            elementValidated = true;
        // (str.matches(".*([.,/])work\\1$"))
        } else if (Utilities.isAbsoluteUrl(type)) {
            StructureDefinition defn = context.fetchTypeDefinition(type);
            if (defn != null && hasMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep())) {
                List<String> txtype = getMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep());
                if (txtype.contains("CodeableConcept")) {
                    checkTerminologyCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn);
                    thisIsCodeableConcept = true;
                } else if (txtype.contains("Coding")) {
                    checkTerminologyCoding(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack, defn);
                }
            }
        }
    } else {
        if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), checkDefn != null, I18nConstants.VALIDATION_VAL_CONTENT_UNKNOWN, ei.getName()))
            validateElement(hostContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, false, true, null);
    }
    StructureDefinition p = null;
    String tail = null;
    if (profiles.isEmpty()) {
        if (type != null) {
            p = getProfileForType(type, checkDefn.getType());
            // If dealing with a primitive type, then we need to check the current child against
            // the invariants (constraints) on the current element, because otherwise it only gets
            // checked against the primary type's invariants: LLoyd
            // if (p.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
            // checkInvariants(hostContext, errors, ei.path, profile, ei.definition, null, null, resource, ei.element);
            // }
            rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_NOTYPE, type);
        }
    } else if (profiles.size() == 1) {
        String url = profiles.get(0);
        if (url.contains("#")) {
            tail = url.substring(url.indexOf("#") + 1);
            url = url.substring(0, url.indexOf("#"));
        }
        p = this.context.fetchResource(StructureDefinition.class, url);
        rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_UNKNOWN_PROFILE, profiles.get(0));
    } else {
        elementValidated = true;
        HashMap<String, List<ValidationMessage>> goodProfiles = new HashMap<String, List<ValidationMessage>>();
        HashMap<String, List<ValidationMessage>> badProfiles = new HashMap<String, List<ValidationMessage>>();
        for (String typeProfile : profiles) {
            String url = typeProfile;
            tail = null;
            if (url.contains("#")) {
                tail = url.substring(url.indexOf("#") + 1);
                url = url.substring(0, url.indexOf("#"));
            }
            p = this.context.fetchResource(StructureDefinition.class, typeProfile);
            if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_UNKNOWN_PROFILE, typeProfile)) {
                List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
                validateElement(hostContext, profileErrors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
                if (hasErrors(profileErrors))
                    badProfiles.put(typeProfile, profileErrors);
                else
                    goodProfiles.put(typeProfile, profileErrors);
            }
        }
        if (goodProfiles.size() == 1) {
            errors.addAll(goodProfiles.values().iterator().next());
        } else if (goodProfiles.size() == 0) {
            rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOMATCH, StringUtils.join("; ", profiles));
            for (String m : badProfiles.keySet()) {
                p = this.context.fetchResource(StructureDefinition.class, m);
                for (ValidationMessage message : badProfiles.get(m)) {
                    message.setMessage(message.getMessage() + " (validating against " + p.getUrl() + (p.hasVersion() ? "|" + p.getVersion() : "") + " [" + p.getName() + "])");
                    errors.add(message);
                }
            }
        } else {
            warning(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MULTIPLEMATCHES, StringUtils.join("; ", goodProfiles.keySet()));
            for (String m : goodProfiles.keySet()) {
                p = this.context.fetchResource(StructureDefinition.class, m);
                for (ValidationMessage message : goodProfiles.get(m)) {
                    message.setMessage(message.getMessage() + " (validating against " + p.getUrl() + (p.hasVersion() ? "|" + p.getVersion() : "") + " [" + p.getName() + "])");
                    errors.add(message);
                }
            }
        }
    }
    if (p != null) {
        trackUsage(p, hostContext, element);
        if (!elementValidated) {
            if (ei.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || ei.getElement().getSpecial() == SpecialElement.BUNDLE_OUTCOME || ei.getElement().getSpecial() == SpecialElement.PARAMETER)
                validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, checkDefn, ei.getElement(), ei.getElement(), type, localStack.resetIds(), thisIsCodeableConcept, checkDisplay, thisExtension);
            else
                validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
        }
        int index = profile.getSnapshot().getElement().indexOf(checkDefn);
        if (index < profile.getSnapshot().getElement().size() - 1) {
            String nextPath = profile.getSnapshot().getElement().get(index + 1).getPath();
            if (!nextPath.equals(checkDefn.getPath()) && nextPath.startsWith(checkDefn.getPath()))
                validateElement(hostContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
        }
    }
}
Also used : ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage) HashMap(java.util.HashMap) NamedElement(org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) Element(org.hl7.fhir.r5.elementmodel.Element) ArrayList(java.util.ArrayList) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) ContactPoint(org.hl7.fhir.r5.model.ContactPoint) StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ArrayList(java.util.ArrayList) List(java.util.List) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition)

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