private IReadOnlyList <ISearchValue> ExtractSearchValues(
            string searchParameterDefinitionUrl,
            SearchParamType?searchParameterType,
            IReadOnlyList <string> allowedReferenceResourceTypes,
            ITypedElement element,
            string fhirPathExpression,
            EvaluationContext context)
        {
            Debug.Assert(searchParameterType != SearchParamType.Composite, "The search parameter must be non-composite.");

            var results = new List <ISearchValue>();

            // For simple value type, we can parse the expression directly.
            IEnumerable <ITypedElement> extractedValues = Enumerable.Empty <ITypedElement>();

            try
            {
                extractedValues = element.Select(fhirPathExpression, context);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(
                    ex,
                    "Failed to extract the values using '{FhirPathExpression}' against '{ElementType}'.",
                    fhirPathExpression,
                    element.GetType());
            }

            Debug.Assert(extractedValues != null, "The extracted values should not be null.");

            // If there is target set, then filter the extracted values to only those types.
            if (searchParameterType == SearchParamType.Reference &&
                allowedReferenceResourceTypes?.Count > 0)
            {
                List <string> targetResourceTypes = _targetTypesLookup.GetOrAdd(searchParameterDefinitionUrl, _ =>
                {
                    return(allowedReferenceResourceTypes.Select(t => t.ToString()).ToList());
                });

                // TODO: The expression for reference search parameters in STU3 has issues.
                // The reference search parameter could be pointing to an element that can be multiple types. For example,
                // the Appointment.participant.actor can be type of Patient, Practitioner, Related Person, Location, and so on.
                // Some search parameter could refer to this property but restrict to certain types. For example,
                // Appointment's location search parameter is returned only when Appointment.participant.actor is Location element.
                // The STU3 expressions don't have this restriction so everything is being returned. This is addressed in R4 release (see
                // http://community.fhir.org/t/expression-seems-incorrect-for-reference-search-parameter-thats-only-applicable-to-certain-types/916/2).
                // Therefore, for now, we will need to compare the reference value itself (which can be internal or external references), and restrict
                // the values ourselves.
                extractedValues = extractedValues.Where(ev =>
                {
                    if (ev.InstanceType.Equals("ResourceReference", StringComparison.OrdinalIgnoreCase))
                    {
                        return(ev.Scalar("reference") is string rr && targetResourceTypes.Any(trt => rr.Contains(trt, StringComparison.Ordinal)));
                    }

                    return(true);
                });
            }

            foreach (var extractedValue in extractedValues)
            {
                if (!_fhirElementTypeConverterManager.TryGetConverter(extractedValue.InstanceType, GetSearchValueTypeForSearchParamType(searchParameterType), out ITypedElementToSearchValueConverter converter))
                {
                    _logger.LogWarning(
                        "The FHIR element '{ElementType}' is not supported.",
                        extractedValue.InstanceType);

                    continue;
                }

                IEnumerable <ISearchValue> searchValues = converter.ConvertTo(extractedValue);

                if (searchValues != null)
                {
                    if (searchParameterType == SearchParamType.Reference && allowedReferenceResourceTypes?.Count == 1)
                    {
                        // For references, if the type is not specified in the reference string, we can set the type on the search value because
                        // in this case it can only be of one type.
                        string singleAllowedResourceType = allowedReferenceResourceTypes[0];
                        foreach (ISearchValue searchValue in searchValues)
                        {
                            if (searchValue is ReferenceSearchValue rsr && string.IsNullOrEmpty(rsr.ResourceType))
                            {
                                results.Add(new ReferenceSearchValue(rsr.Kind, rsr.BaseUri, singleAllowedResourceType, rsr.ResourceId));
                            }
                            else
                            {
                                results.Add(searchValue);
                            }
                        }
                    }