public void TestResolve()
        {
            var statement = "Bundle.entry.where(fullUrl = 'http://example.org/fhir/Patient/e')" +
                            ".resource.managingOrganization.resolve().id";

            var result = _bundleElement.Select(statement);

            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("orgY", result.First().Value);

            //var resultPoco = _parsed.Select(statement).SingleOrDefault() as Organization;
            //Assert.IsNotNull(resultPoco);
            //Assert.AreEqual("orgY", resultPoco.Id);
        }
Exemplo n.º 2
0
        public SearchParameterWrapper(ITypedElement searchParameter)
        {
            EnsureArg.IsNotNull(searchParameter, nameof(searchParameter));
            EnsureArg.Is(KnownResourceTypes.SearchParameter, searchParameter.InstanceType, StringComparison.Ordinal, nameof(searchParameter));

            _name        = new Lazy <string>(() => searchParameter.Scalar("name")?.ToString());
            _description = new Lazy <string>(() => searchParameter.Scalar("description")?.ToString());
            _url         = new Lazy <string>(() => searchParameter.Scalar("url")?.ToString());
            _expression  = new Lazy <string>(() => searchParameter.Scalar("expression")?.ToString());
            _type        = new Lazy <string>(() => searchParameter.Scalar("type")?.ToString());

            _base      = new Lazy <IReadOnlyList <string> >(() => searchParameter.Select("base")?.AsStringValues().ToArray());
            _component = new Lazy <IReadOnlyList <ITypedElement> >(() => searchParameter.Select("component")?.ToArray());
            _target    = new Lazy <IReadOnlyList <string> >(() => searchParameter.Select("target")?.AsStringValues().ToArray());
        }
Exemplo n.º 3
0
        public static void CheckBundleEntryNavigation(ITypedElement node)
        {
            var entryNav = node.Select("entry.resource").First();
            var id       = entryNav.Scalar("id");

            Assert.IsNotNull(id);
        }
        protected override IEnumerable <ISearchValue> Convert(ITypedElement value)
        {
            // Based on spec: http://hl7.org/fhir/search.html#token,
            // CodeableConcept.text is searchable, but we will only create a dedicated entry for it
            // if it is different from the display text of one of its codings

            string text = value.Scalar("text") as string;
            bool   conceptTextNeedsToBeAdded = !string.IsNullOrWhiteSpace(text);

            foreach (ITypedElement coding in value.Select("coding"))
            {
                TokenSearchValue searchValue = coding?.ToTokenSearchValue();

                if (searchValue != null)
                {
                    if (conceptTextNeedsToBeAdded)
                    {
                        conceptTextNeedsToBeAdded = !string.Equals(text, searchValue.Text, StringComparison.OrdinalIgnoreCase);
                    }

                    yield return(searchValue);
                }
            }

            if (conceptTextNeedsToBeAdded)
            {
                yield return(new TokenSearchValue(null, null, text));
            }
        }
        private IEnumerable <ITypedElement> GetMatchNodes(AnonymizationFhirPathRule rule, ITypedElement node)
        {
            var typeMatch = AnonymizationFhirPathRule.TypeRuleRegex.Match(rule.Path);
            var nameMatch = AnonymizationFhirPathRule.NameRuleRegex.Match(rule.Path);

            if (typeMatch.Success)
            {
                return(GetMatchNodesFromLookUp(_typeToNodeLookUp, typeMatch.Groups["type"].Value, typeMatch.Groups["expression"].Value));
            }

            if (nameMatch.Success)
            {
                return(GetMatchNodesFromLookUp(_nameToNodeLookUp, nameMatch.Groups["name"].Value, nameMatch.Groups["expression"].Value));
            }

            /*
             * Special case handling:
             * Senario: FHIR path only contains resourceType: Patient, Resource.
             * Sample AnonymizationFhirPathRule: { "path": "Patient", "method": "keep" }
             *
             * Current FHIR path lib do not support navigate such ResourceType FHIR path from resource in bundle.
             * Example: navigate with FHIR path "Patient" from "Bundle.entry[0].resource[0]" is not support
             */
            return(rule.IsResourceTypeRule ? new List <ITypedElement> {
                node
            } : node.Select(rule.Expression).ToList());
        }
Exemplo n.º 6
0
        public BundleWrapper(ITypedElement bundle)
        {
            EnsureArg.IsNotNull(bundle, nameof(bundle));
            EnsureArg.Is(KnownResourceTypes.Bundle, bundle.InstanceType, StringComparison.Ordinal, nameof(bundle));

            _entries = new Lazy <IReadOnlyList <BundleEntryWrapper> >(() => bundle.Select("entry").Select(x => new BundleEntryWrapper(x)).ToArray());
        }
        private IEnumerable <SearchIndexEntry> ProcessCompositeSearchParameter(SearchParameterInfo searchParameter, ITypedElement resource, EvaluationContext context)
        {
            Debug.Assert(searchParameter?.Type == SearchParamType.Composite, "The search parameter must be composite.");

            SearchParameterInfo compositeSearchParameterInfo = searchParameter;

            IEnumerable <ITypedElement> rootObjects = resource.Select(searchParameter.Expression, context);

            foreach (var rootObject in rootObjects)
            {
                int  numberOfComponents = searchParameter.Component.Count;
                bool skip = false;

                var componentValues = new IReadOnlyList <ISearchValue> [numberOfComponents];

                // For each object extracted from the expression, we will need to evaluate each component.
                for (int i = 0; i < numberOfComponents; i++)
                {
                    SearchParameterComponentInfo component = searchParameter.Component[i];

                    // First find the type of the component.
                    SearchParameterInfo componentSearchParameterDefinition = searchParameter.Component[i].ResolvedSearchParameter;

                    IReadOnlyList <ISearchValue> extractedComponentValues = ExtractSearchValues(
                        componentSearchParameterDefinition.Url.ToString(),
                        componentSearchParameterDefinition.Type,
                        componentSearchParameterDefinition.TargetResourceTypes,
                        rootObject,
                        component.Expression,
                        context);

                    // Filter out any search value that's not valid as a composite component.
                    extractedComponentValues = extractedComponentValues
                                               .Where(sv => sv.IsValidAsCompositeComponent)
                                               .ToArray();

                    if (!extractedComponentValues.Any())
                    {
                        // One of the components didn't have any value and therefore it will not be indexed.
                        skip = true;
                        break;
                    }

                    componentValues[i] = extractedComponentValues;
                }

                if (skip)
                {
                    continue;
                }

                yield return(new SearchIndexEntry(compositeSearchParameterInfo, new CompositeSearchValue(componentValues)));
            }
        }
Exemplo n.º 8
0
        public void TestStringSplit()
        {
            ITypedElement dummy  = ElementNode.ForPrimitive("a,b,c,d");
            var           result = dummy.Select("split(',')");

            Assert.IsNotNull(result);
            CollectionAssert.AreEqual(new[] { "a", "b", "c", "d" }, result.Select(r => r.Value.ToString()).ToArray());

            dummy  = ElementNode.ForPrimitive("a,,b,c,d"); // Empty element should be removed
            result = dummy.Select("split(',')");
            Assert.IsNotNull(result);
            CollectionAssert.AreEqual(new[] { "a", "b", "c", "d" }, result.Select(r => r.Value.ToString()).ToArray());

            dummy  = ElementNode.ForPrimitive("");
            result = dummy.Select("split(',')");
            Assert.IsNotNull(result);

            dummy  = ElementNode.ForPrimitive("[stop]ONE[stop][stop]TWO[stop][stop][stop]THREE[stop][stop]");
            result = dummy.Select("split('[stop]')");
            Assert.IsNotNull(result);
            CollectionAssert.AreEqual(new[] { "ONE", "TWO", "THREE" }, result.Select(r => r.Value.ToString()).ToArray());
        }
        protected override IEnumerable <ISearchValue> Convert(ITypedElement value)
        {
            // http://hl7.org/fhir/patient.html recommends the following:
            // A server defined search that may match any of the string fields in the Address, including line, city, state, country, postalCode, and/or text.
            // we will do a basic search based on any of the address component for now. Details on localization will be handled later.

            var city     = value.Scalar("city") as string;
            var country  = value.Scalar("country") as string;
            var district = value.Scalar("district") as string;
            IEnumerable <ITypedElement> lines = value.Select("line");
            var postCode = value.Scalar("postalCode") as string;
            var state    = value.Scalar("state") as string;
            var text     = value.Scalar("text") as string;

            if (!string.IsNullOrWhiteSpace(city))
            {
                yield return(new StringSearchValue(city));
            }

            if (!string.IsNullOrWhiteSpace(country))
            {
                yield return(new StringSearchValue(country));
            }

            if (!string.IsNullOrWhiteSpace(district))
            {
                yield return(new StringSearchValue(district));
            }

            foreach (var line in lines.AsStringValues())
            {
                yield return(new StringSearchValue(line));
            }

            if (!string.IsNullOrWhiteSpace(postCode))
            {
                yield return(new StringSearchValue(postCode));
            }

            if (!string.IsNullOrWhiteSpace(state))
            {
                yield return(new StringSearchValue(state));
            }

            if (!string.IsNullOrWhiteSpace(text))
            {
                yield return(new StringSearchValue(text));
            }
        }
Exemplo n.º 10
0
        protected override IEnumerable <ISearchValue> Convert(ITypedElement value)
        {
            IEnumerable <ITypedElement> givenNames = value.Select("given");
            IEnumerable <ITypedElement> prefixes   = value.Select("prefix");
            IEnumerable <ITypedElement> suffixes   = value.Select("suffix");
            var family = value.Scalar("family") as string;
            var text   = value.Scalar("text") as string;

            // https://www.hl7.org/fhir/patient.html recommends the following:
            // A server defined search that may match any of the string fields in the HumanName, including family, give, prefix, suffix, suffix, and/or text
            // we will do a basic search based on family or given or prefix or suffix or text for now. Details on localization will be handled later.
            foreach (var given in givenNames.AsStringValues())
            {
                yield return(new StringSearchValue(given));
            }

            if (!string.IsNullOrWhiteSpace(family))
            {
                yield return(new StringSearchValue(family));
            }

            foreach (var prefix in prefixes.AsStringValues())
            {
                yield return(new StringSearchValue(prefix));
            }

            foreach (var suffix in suffixes.AsStringValues())
            {
                yield return(new StringSearchValue(suffix));
            }

            if (!string.IsNullOrWhiteSpace(text))
            {
                yield return(new StringSearchValue(text));
            }
        }
Exemplo n.º 11
0
        public IEnumerable <ITypedElement>?Select(IFhirResourceStu3 fhirResource, string Expression)
        {
            ITypedElement TypedElement = fhirResource.Stu3.ToTypedElement();
            //FhirPathCompiler.DefaultSymbolTable.AddFhirExtensions();
            var oFhirEvaluationContext = new Hl7.Fhir.FhirPath.FhirEvaluationContext(TypedElement);

            //The resolve() function then also needs to be provided an external resolver delegate that performs the resolve
            //that delegate can be set as below. Here I am providing my own implementation 'IPyroFhirPathResolve.Resolver'
            //oFhirEvaluationContext.ElementResolver = IPyroFhirPathResolve.Resolver;
            try
            {
                return(TypedElement.Select(Expression, oFhirEvaluationContext));
            }
            catch (Exception Exec)
            {
                throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, $"Unable to evaluate the SearchParameter FhirPath expression of: {Expression} for FHIR {FhirVersion.Stu3.GetCode()}. See inner exception for more info.", Exec);
            }
        }
Exemplo n.º 12
0
        static void Main(string[] args)
        {
            var xml = "<Patient xmlns=\"http://hl7.org/fhir\"><identifier>" +
                      "<use value=\"official\" /></identifier></Patient>";
            MemoryStream memStream = new MemoryStream();

            byte[] data = Encoding.Default.GetBytes(xml);
            memStream.Write(data, 0, data.Length);
            memStream.Position = 0;
            XmlReader reader = XmlReader.Create(memStream);

            reader.Read();

            FhirXmlParsingSettings settings = new FhirXmlParsingSettings();

            ISourceNode patientNode = FhirXmlNode.Read(reader, settings);
            //IResourceResolver Resolver = new TestResourceResolver();
            IResourceResolver Resolver = ZipSource.CreateValidationSource();


            StructureDefinitionSummaryProvider Provider = new StructureDefinitionSummaryProvider(Resolver);



            ITypedElement patientRootElement = patientNode.ToTypedElement(Provider);

            var    r    = patientRootElement.Select("Patient.identifier.use");
            string test = (string)r.FirstOrDefault().Value;

            //ITypedElement activeElement = patientRootElement.Children("active").First();
            //Assert.AreEqual("boolean", activeElement.Type);

            //Assert.AreEqual("boolean", activeElement.Type);


            //var patientNode = FhirXmlNode.Parse(xml);
            //var use = patientNode.Children("identifier").Children("use").First();
            //Assert.AreEqual("official", use.Text);
            //Assert.AreEqual("Patient.identifier[0].use[0]", use.Location);
        }
        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);
                            }
                        }
                    }
Exemplo n.º 14
0
        internal BundleEntryWrapper(ITypedElement entry)
        {
            EnsureArg.IsNotNull(entry, nameof(entry));

            _entry = new Lazy <ITypedElement>(() => entry.Select("resource").FirstOrDefault());
        }