Search in sources :

Example 1 with TypedElementDefinition

use of org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition in project org.hl7.fhir.core by hapifhir.

the class FHIRPathEngine method evaluateDefinition.

/**
 * given an element definition in a profile, what element contains the differentiating fixed
 * for the element, given the differentiating expresssion. The expression is only allowed to
 * use a subset of FHIRPath
 *
 * @param profile
 * @param element
 * @return
 * @throws PathEngineException
 * @throws DefinitionException
 */
public TypedElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, TypedElementDefinition element, StructureDefinition source, boolean dontWalkIntoReferences) throws DefinitionException {
    StructureDefinition sd = profile;
    TypedElementDefinition focus = null;
    boolean okToNotResolve = false;
    if (expr.getKind() == Kind.Name) {
        if (element.getElement().hasSlicing()) {
            ElementDefinition slice = pickMandatorySlice(sd, element.getElement());
            if (slice == null) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getElement().getId());
            }
            element = new TypedElementDefinition(slice);
        }
        if (expr.getName().equals("$this")) {
            focus = element;
        } else {
            List<ElementDefinition> childDefinitions;
            childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
            // if that's empty, get the children of the type
            if (childDefinitions.isEmpty()) {
                sd = fetchStructureByType(element, expr);
                if (sd == null) {
                    throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getElement().getType().get(0).getProfile(), element.getElement().getId());
                }
                childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep());
            }
            for (ElementDefinition t : childDefinitions) {
                if (tailMatches(t, expr.getName()) && !t.hasSlicing()) {
                    // GG: slicing is a problem here. This is for an exetnsion with a fixed value (type slicing)
                    focus = new TypedElementDefinition(t);
                    break;
                }
            }
        }
    } else if (expr.getKind() == Kind.Function) {
        if ("resolve".equals(expr.getName())) {
            if (element.getTypes().size() == 0) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getElement().getId());
            }
            if (element.getTypes().size() > 1) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getElement().getId());
            }
            if (!element.getTypes().get(0).hasTarget()) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getElement().getId(), element.getElement().getType().get(0).getCode() + ")");
            }
            if (element.getTypes().get(0).getTargetProfile().size() > 1) {
                throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getElement().getId());
            }
            sd = worker.fetchResource(StructureDefinition.class, element.getTypes().get(0).getTargetProfile().get(0).getValue());
            if (sd == null) {
                throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getTypes().get(0).getTargetProfile(), element.getElement().getId());
            }
            focus = new TypedElementDefinition(sd.getSnapshot().getElementFirstRep());
        } else if ("extension".equals(expr.getName())) {
            String targetUrl = expr.getParameters().get(0).getConstant().primitiveValue();
            List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
            for (ElementDefinition t : childDefinitions) {
                if (t.getPath().endsWith(".extension") && t.hasSliceName()) {
                    System.out.println("t: " + t.getId());
                    StructureDefinition exsd = (t.getType() == null || t.getType().isEmpty() || t.getType().get(0).getProfile().isEmpty()) ? null : worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue());
                    while (exsd != null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) {
                        exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition());
                    }
                    if (exsd != null && exsd.getUrl().equals(targetUrl)) {
                        if (profileUtilities.getChildMap(sd, t).isEmpty()) {
                            sd = exsd;
                        }
                        focus = new TypedElementDefinition(t);
                        break;
                    }
                }
            }
            if (focus == null) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND_EXTENSION, expr.toString(), targetUrl, element.getElement().getId(), sd.getUrl());
            }
        } else if ("ofType".equals(expr.getName())) {
            if (!element.getElement().hasType()) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getElement().getId());
            }
            List<String> atn = new ArrayList<>();
            for (TypeRefComponent tr : element.getTypes()) {
                if (!tr.hasCode()) {
                    throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getElement().getId());
                }
                atn.add(tr.getCode());
            }
            String stn = expr.getParameters().get(0).getName();
            okToNotResolve = true;
            if ((atn.contains(stn))) {
                if (element.getTypes().size() > 1) {
                    focus = new TypedElementDefinition(element.getElement(), stn);
                } else {
                    focus = element;
                }
            }
        } else {
            throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName());
        }
    } else if (expr.getKind() == Kind.Group) {
        throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP, expr.toString());
    } else if (expr.getKind() == Kind.Constant) {
        throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST);
    }
    if (focus == null) {
        if (okToNotResolve) {
            return null;
        } else {
            throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString(), source.getUrl(), element.getElement().getId(), profile.getUrl());
        }
    } else {
        // gdg 26-02-2022. If we're walking towards a resolve() and we're on a reference, and  we try to walk into the reference
        // then we don't do that. .resolve() is allowed on the Reference.reference, but the target of the reference will be defined
        // on the Reference, not the reference.reference.
        ExpressionNode next = expr.getInner();
        if (dontWalkIntoReferences && focus.hasType("Reference") && next != null && next.getKind() == Kind.Name && next.getName().equals("reference")) {
            next = next.getInner();
        }
        if (next == null) {
            return focus;
        } else {
            return evaluateDefinition(next, sd, focus, profile, dontWalkIntoReferences);
        }
    }
}
Also used : StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ExpressionNode(org.hl7.fhir.r5.model.ExpressionNode) MergedList(org.hl7.fhir.utilities.MergedList) List(java.util.List) ArrayList(java.util.ArrayList) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition)

Example 2 with TypedElementDefinition

use of org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method getCriteriaForDiscriminator.

private List<ElementDefinition> getCriteriaForDiscriminator(String path, ElementDefinition element, String discriminator, StructureDefinition profile, boolean removeResolve, StructureDefinition srcProfile) throws FHIRException {
    List<ElementDefinition> elements = new ArrayList<ElementDefinition>();
    if ("value".equals(discriminator) && element.hasFixed()) {
        elements.add(element);
        return elements;
    }
    boolean dontFollowReference = false;
    if (removeResolve) {
        // if we're doing profile slicing, we don't want to walk into the last resolve.. we need the profile on the source not the target
        if (discriminator.equals("resolve()")) {
            elements.add(element);
            return elements;
        }
        if (discriminator.endsWith(".resolve()")) {
            discriminator = discriminator.substring(0, discriminator.length() - 10);
            dontFollowReference = true;
        }
    }
    TypedElementDefinition ted = null;
    String fp = fixExpr(discriminator, null);
    ExpressionNode expr = null;
    try {
        expr = fpe.parse(fp);
    } catch (Exception e) {
        if (STACK_TRACE)
            e.printStackTrace();
        throw new FHIRException(context.formatMessage(I18nConstants.DISCRIMINATOR_BAD_PATH, e.getMessage(), fp), e);
    }
    long t2 = System.nanoTime();
    ted = fpe.evaluateDefinition(expr, profile, new TypedElementDefinition(element), srcProfile, dontFollowReference);
    timeTracker.sd(t2);
    if (ted != null)
        elements.add(ted.getElement());
    for (TypeRefComponent type : element.getType()) {
        for (CanonicalType p : type.getProfile()) {
            String id = p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT) ? p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT) : null;
            StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue());
            if (sd == null)
                throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE_, p));
            profile = sd;
            if (id == null)
                element = sd.getSnapshot().getElementFirstRep();
            else {
                element = null;
                for (ElementDefinition t : sd.getSnapshot().getElement()) {
                    if (id.equals(t.getId()))
                        element = t;
                }
                if (element == null)
                    throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ELEMENT__IN_PROFILE_, id, p));
            }
            expr = fpe.parse(fp);
            t2 = System.nanoTime();
            ted = fpe.evaluateDefinition(expr, profile, new TypedElementDefinition(element), srcProfile, dontFollowReference);
            timeTracker.sd(t2);
            if (ted != null)
                elements.add(ted.getElement());
        }
    }
    return elements;
}
Also used : TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ArrayList(java.util.ArrayList) FHIRException(org.hl7.fhir.exceptions.FHIRException) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) TerminologyServiceException(org.hl7.fhir.exceptions.TerminologyServiceException) DefinitionException(org.hl7.fhir.exceptions.DefinitionException) IOException(java.io.IOException) FHIRException(org.hl7.fhir.exceptions.FHIRException) NotImplementedException(org.apache.commons.lang3.NotImplementedException) PathEngineException(org.hl7.fhir.exceptions.PathEngineException) FHIRLexerException(org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException) StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ExpressionNode(org.hl7.fhir.r5.model.ExpressionNode) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition) DefinitionException(org.hl7.fhir.exceptions.DefinitionException)

Example 3 with TypedElementDefinition

use of org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition in project org.hl7.fhir.core by hapifhir.

the class FHIRPathEngine method evaluateDefinition.

/**
 * given an element definition in a profile, what element contains the differentiating fixed
 * for the element, given the differentiating expresssion. The expression is only allowed to
 * use a subset of FHIRPath
 *
 * @param profile
 * @param element
 * @return
 * @throws PathEngineException
 * @throws DefinitionException
 */
public TypedElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, TypedElementDefinition element, StructureDefinition source) throws DefinitionException {
    StructureDefinition sd = profile;
    TypedElementDefinition focus = null;
    boolean okToNotResolve = false;
    if (expr.getKind() == Kind.Name) {
        if (element.getElement().hasSlicing()) {
            ElementDefinition slice = pickMandatorySlice(sd, element.getElement());
            if (slice == null) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getElement().getId());
            }
            element = new TypedElementDefinition(slice);
        }
        if (expr.getName().equals("$this")) {
            focus = element;
        } else {
            List<ElementDefinition> childDefinitions;
            childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
            // if that's empty, get the children of the type
            if (childDefinitions.isEmpty()) {
                sd = fetchStructureByType(element, expr);
                if (sd == null) {
                    throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getElement().getType().get(0).getProfile(), element.getElement().getId());
                }
                childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep());
            }
            for (ElementDefinition t : childDefinitions) {
                if (tailMatches(t, expr.getName()) && !t.hasSlicing()) {
                    // GG: slicing is a problem here. This is for an exetnsion with a fixed value (type slicing)
                    focus = new TypedElementDefinition(t);
                    break;
                }
            }
        }
    } else if (expr.getKind() == Kind.Function) {
        if ("resolve".equals(expr.getName())) {
            if (element.getTypes().size() == 0) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getElement().getId());
            }
            if (element.getTypes().size() > 1) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getElement().getId());
            }
            if (!element.getTypes().get(0).hasTarget()) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getElement().getId(), element.getElement().getType().get(0).getCode() + ")");
            }
            if (element.getTypes().get(0).getTargetProfile().size() > 1) {
                throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getElement().getId());
            }
            sd = worker.fetchResource(StructureDefinition.class, element.getTypes().get(0).getTargetProfile().get(0).getValue());
            if (sd == null) {
                throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getTypes().get(0).getTargetProfile(), element.getElement().getId());
            }
            focus = new TypedElementDefinition(sd.getSnapshot().getElementFirstRep());
        } else if ("extension".equals(expr.getName())) {
            String targetUrl = expr.getParameters().get(0).getConstant().primitiveValue();
            List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
            for (ElementDefinition t : childDefinitions) {
                if (t.getPath().endsWith(".extension") && t.hasSliceName()) {
                    System.out.println("t: " + t.getId());
                    StructureDefinition exsd = (t.getType() == null || t.getType().isEmpty() || t.getType().get(0).getProfile().isEmpty()) ? null : worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue());
                    while (exsd != null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) {
                        exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition());
                    }
                    if (exsd != null && exsd.getUrl().equals(targetUrl)) {
                        if (profileUtilities.getChildMap(sd, t).isEmpty()) {
                            sd = exsd;
                        }
                        focus = new TypedElementDefinition(t);
                        break;
                    }
                }
            }
            if (focus == null) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND_EXTENSION, expr.toString(), targetUrl, element.getElement().getId(), sd.getUrl());
            }
        } else if ("ofType".equals(expr.getName())) {
            if (!element.getElement().hasType()) {
                throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getElement().getId());
            }
            List<String> atn = new ArrayList<>();
            for (TypeRefComponent tr : element.getTypes()) {
                if (!tr.hasCode()) {
                    throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getElement().getId());
                }
                atn.add(tr.getCode());
            }
            String stn = expr.getParameters().get(0).getName();
            okToNotResolve = true;
            if ((atn.contains(stn))) {
                if (element.getTypes().size() > 1) {
                    focus = new TypedElementDefinition(element.getElement(), stn);
                } else {
                    focus = element;
                }
            }
        } else {
            throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName());
        }
    } else if (expr.getKind() == Kind.Group) {
        throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP, expr.toString());
    } else if (expr.getKind() == Kind.Constant) {
        throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST);
    }
    if (focus == null) {
        if (okToNotResolve) {
            return null;
        } else {
            throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString(), source.getUrl(), element.getElement().getId(), profile.getUrl());
        }
    } else if (expr.getInner() == null) {
        return focus;
    } else {
        return evaluateDefinition(expr.getInner(), sd, focus, profile);
    }
}
Also used : StructureDefinition(org.hl7.fhir.r4b.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r4b.model.ElementDefinition.TypeRefComponent) MergedList(org.hl7.fhir.utilities.MergedList) List(java.util.List) ArrayList(java.util.ArrayList) ElementDefinition(org.hl7.fhir.r4b.model.ElementDefinition)

Aggregations

ArrayList (java.util.ArrayList)3 List (java.util.List)2 ElementDefinition (org.hl7.fhir.r5.model.ElementDefinition)2 TypeRefComponent (org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent)2 ExpressionNode (org.hl7.fhir.r5.model.ExpressionNode)2 StructureDefinition (org.hl7.fhir.r5.model.StructureDefinition)2 MergedList (org.hl7.fhir.utilities.MergedList)2 IOException (java.io.IOException)1 NotImplementedException (org.apache.commons.lang3.NotImplementedException)1 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)1 FHIRException (org.hl7.fhir.exceptions.FHIRException)1 PathEngineException (org.hl7.fhir.exceptions.PathEngineException)1 TerminologyServiceException (org.hl7.fhir.exceptions.TerminologyServiceException)1 ElementDefinition (org.hl7.fhir.r4b.model.ElementDefinition)1 TypeRefComponent (org.hl7.fhir.r4b.model.ElementDefinition.TypeRefComponent)1 StructureDefinition (org.hl7.fhir.r4b.model.StructureDefinition)1 CanonicalType (org.hl7.fhir.r5.model.CanonicalType)1 FHIRLexerException (org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException)1 TypedElementDefinition (org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition)1