示例#1
0
        private static CompiledExpression getCompiledExpression(string expression, FhirPathCompiler compiler = null)
        {
            lock (_cacheLock)
            {
                bool success = _cache.TryGetValue(expression, out CompiledExpression ce);

                if (!success)
                {
                    var internalCompiler = compiler ?? new FhirPathCompiler();
                    ce = internalCompiler.Compile(expression);

                    if (_cache.Count >= MAX_FP_EXPRESSION_CACHE_SIZE)
                    {
                        var lruExpression = _mruList.First();
                        _cache.Remove(lruExpression);
                        _mruList.Remove(lruExpression);
                    }

                    _cache.Add(expression, ce);
                }

                _mruList.Remove(expression);
                _mruList.Add(expression);

                return(ce);
            }
        }
示例#2
0
        public void Validate(AnonymizerConfiguration config)
        {
            if (config.FhirPathRules == null)
            {
                throw new AnonymizerConfigurationErrorsException("The configuration is invalid, please specify any fhirPathRules");
            }

            FhirPathCompiler compiler = new FhirPathCompiler();

            foreach (var rule in config.FhirPathRules)
            {
                if (!rule.ContainsKey(Constants.PathKey) || !rule.ContainsKey(Constants.MethodKey))
                {
                    throw new AnonymizerConfigurationErrorsException("Missing path or method in Fhir path rule config.");
                }

                // Grammar check on FHIR path
                try
                {
                    compiler.Compile(rule[Constants.PathKey]);
                }
                catch (Exception ex)
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid FHIR path {rule[Constants.PathKey]}", ex);
                }

                // Method validate
                string method = rule[Constants.MethodKey];
                if (!Enum.TryParse <AnonymizerMethod>(method, true, out _))
                {
                    throw new AnonymizerConfigurationErrorsException($"{method} not support.");
                }
            }
        }
        public CompiledExpressionOutCome GetCompiledExpression(Resource Resource, ParseExpressionOutCome ParseExpressionOutCome)
        {
            CompiledExpressionOutCome CompiledExpressionOutCome = new CompiledExpressionOutCome();

            CompiledExpressionOutCome.ParseExpressionOutCome = ParseExpressionOutCome;

            FhirPathCompiler Compiler = new FhirPathCompiler();
            var PocoNavigator         = new Hl7.Fhir.ElementModel.PocoNavigator(Resource);

            try
            {
                CompiledExpressionOutCome.CompiledExpression = Compiler.Compile(ParseExpressionOutCome.ExpressionString);
            }
            catch (Exception ex)
            {
                CompiledExpressionOutCome.Ok           = false;
                CompiledExpressionOutCome.ErrorMessage = ex.Message;
                return(CompiledExpressionOutCome);
            }
            if (CompiledExpressionOutCome.CompiledExpression != null)
            {
                CompiledExpressionOutCome.Ok = CompiledExpressionOutCome.CompiledExpression.Predicate(PocoNavigator, new Hl7.Fhir.FhirPath.FhirEvaluationContext(PocoNavigator));
            }
            return(CompiledExpressionOutCome);
        }
        public ElementNode AnonymizeResourceNode(ElementNode root)
        {
            EnsureArg.IsNotNull(root, nameof(root));

            if (root.IsBundleNode())
            {
                var entryResources = root.GetEntryResourceChildren();
                AnonymizeInternalResourceNodes(entryResources);
            }

            if (root.HasContainedNode())
            {
                var containedResources = root.GetContainedChildren();
                AnonymizeInternalResourceNodes(containedResources);
            }

            var resourceContext = ResourceAnonymizerContext.Create(root, _configurationManger);

            foreach (var rule in resourceContext.RuleList)
            {
                var pathCompileExpression = new FhirPathCompiler().Compile($"{rule.Path}");
                var matchedNodes          = pathCompileExpression(root, EvaluationContext.CreateDefault())
                                            .Cast <ElementNode>();
                foreach (var node in matchedNodes)
                {
                    AnonymizeChildNode(node, rule.Method, resourceContext.PathSet);
                }
            }

            return(root);
        }
示例#5
0
        public void TestTreeVisualizerVisitor()
        {
            var compiler = new FhirPathCompiler();
            var expr     = compiler.Parse("doSomething('ha!', 4, {}, $this, somethingElse(true))");
            var result   = expr.Dump();

            Debug.WriteLine(result);
        }
示例#6
0
        static SearchParameterFixtureData()
        {
            FhirPathCompiler.DefaultSymbolTable.AddFhirExtensions();

            Compiler = new FhirPathCompiler();
            Manager  = CreateFhirElementToSearchValueTypeConverterManager();
            SearchDefinitionManager = CreateSearchParameterDefinitionManager(new VersionSpecificModelInfoProvider());
        }
        public static void ValidateRuleSettings(Dictionary <string, object> ruleSettings)
        {
            var compiler = new FhirPathCompiler();

            if (ruleSettings == null)
            {
                throw new AnonymizerConfigurationErrorsException("Generalize rule should not be null.");
            }

            if (!ruleSettings.ContainsKey(Constants.PathKey))
            {
                throw new AnonymizerConfigurationErrorsException("Missing path in FHIR path rule config.");
            }

            if (!ruleSettings.ContainsKey(Constants.MethodKey))
            {
                throw new AnonymizerConfigurationErrorsException("Missing method in FHIR path rule config.");
            }

            if (!ruleSettings.ContainsKey(RuleKeys.Cases))
            {
                throw new AnonymizerConfigurationErrorsException("Missing cases in FHIR path rule config.");
            }

            try
            {
                var cases = (Dictionary <object, object>)ruleSettings.GetValueOrDefault(RuleKeys.Cases);
                foreach (var eachCase in cases)
                {
                    compiler.Compile(eachCase.Key.ToString());
                    compiler.Compile(eachCase.Value.ToString());
                }
            }
            catch (JsonReaderException ex)
            {
                throw new AnonymizerConfigurationErrorsException(
                          $"Invalid Json format {ruleSettings.GetValueOrDefault(RuleKeys.Cases)}", ex);
            }
            catch (Exception ex)
            {
                throw new AnonymizerConfigurationErrorsException(
                          $"Invalid cases expression {ruleSettings.GetValueOrDefault(RuleKeys.Cases)}", ex);
            }

            var supportedOtherValuesOperations = Enum.GetNames(typeof(GeneralizationOtherValuesOperation))
                                                 .ToHashSet(StringComparer.InvariantCultureIgnoreCase);

            if (ruleSettings.ContainsKey(RuleKeys.OtherValues) &&
                !supportedOtherValuesOperations.Contains(ruleSettings[RuleKeys.OtherValues].ToString()))
            {
                throw new AnonymizerConfigurationErrorsException(
                          $"OtherValues setting is invalid at {ruleSettings[RuleKeys.OtherValues]}.");
            }
        }
        public void ResolveOnEmptyTest()
        {
            // resolve should handle an empty collection as input
            var symbolTable = new SymbolTable();

            symbolTable.AddStandardFP();
            symbolTable.AddFhirExtensions();
            var compiler  = new FhirPathCompiler(symbolTable);
            var evaluator = compiler.Compile("{}.resolve()");

            var result = evaluator(null, FhirEvaluationContext.CreateDefault());

            Assert.IsFalse(result.Any());
        }
示例#9
0
        public SearchParameterFixtureData()
        {
            Compiler = new FhirPathCompiler();

            var types = typeof(IFhirElementToSearchValueTypeConverter)
                        .Assembly
                        .GetTypes()
                        .Where(x => typeof(IFhirElementToSearchValueTypeConverter).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface);

            var fhirElementToSearchValueTypeConverters =
                types.Select(x => (IFhirElementToSearchValueTypeConverter)Mock.TypeWithArguments(x));

            Manager = new FhirElementToSearchValueTypeConverterManager(fhirElementToSearchValueTypeConverters);

            SearchDefinitionManager = CreateSearchParameterDefinitionManager();
        }
示例#10
0
        public ParseExpressionOutCome ParseExpression(string Expression)
        {
            var OutCome = new ParseExpressionOutCome();

            OutCome.ExpressionString = Expression;
            FhirPathCompiler Compiler = new FhirPathCompiler();

            try
            {
                OutCome.Expression = Compiler.Parse(Expression);
                OutCome.PasreOk    = true;
                return(OutCome);
            }
            catch (Exception Exec)
            {
                OutCome.PasreOk      = false;
                OutCome.ErrorMessage = Exec.Message;
                return(OutCome);
            }
        }
示例#11
0
        public ParseExpressionOutCome ParseExpression(string Expression)
        {
            var OutCome = new ParseExpressionOutCome();

            OutCome.ExpressionString = Expression;
            Hl7.FhirPath.FhirPathCompiler.DefaultSymbolTable.AddFhirExtensions();
            FhirPathCompiler Compiler = new FhirPathCompiler();

            try
            {
                OutCome.Expression = Compiler.Parse(Expression);
                OutCome.PasreOk    = true;
                return(OutCome);
            }
            catch (Exception Exec)
            {
                OutCome.PasreOk      = false;
                OutCome.ErrorMessage = Exec.Message;
                return(OutCome);
            }
        }
示例#12
0
        public CompiledExpressionOutCome GetCompiledExpression(Resource Resource, ParseExpressionOutCome ParseExpressionOutCome)
        {
            CompiledExpressionOutCome CompiledExpressionOutCome = new CompiledExpressionOutCome();

            CompiledExpressionOutCome.ParseExpressionOutCome = ParseExpressionOutCome;
            Hl7.FhirPath.FhirPathCompiler.DefaultSymbolTable.AddFhirExtensions();
            FhirPathCompiler Compiler = new FhirPathCompiler();

            var PocoNavigator = Resource.ToTypedElement();

            //var PocoNavigator = new Hl7.Fhir.ElementModel.PocoNavigator(Resource);
            try
            {
                CompiledExpressionOutCome.CompiledExpression = Compiler.Compile(ParseExpressionOutCome.ExpressionString);
            }
            catch (Exception ex)
            {
                CompiledExpressionOutCome.Ok           = false;
                CompiledExpressionOutCome.ErrorMessage = ex.Message;
                return(CompiledExpressionOutCome);
            }
            if (CompiledExpressionOutCome.CompiledExpression != null)
            {
                try
                {
                    var oFhirEvaluationContext = new Hl7.Fhir.FhirPath.FhirEvaluationContext(PocoNavigator);
                    oFhirEvaluationContext.ElementResolver = CustomFhirPathResolver.Resolver;
                    CompiledExpressionOutCome.Ok           = CompiledExpressionOutCome.CompiledExpression.Predicate(PocoNavigator, oFhirEvaluationContext);
                }
                catch (System.Exception Exec)
                {
                    CompiledExpressionOutCome.Ok           = false;
                    CompiledExpressionOutCome.ErrorMessage = Exec.Message;
                    return(CompiledExpressionOutCome);
                }
            }
            return(CompiledExpressionOutCome);
        }
示例#13
0
        public ElementNode AnonymizeResourceNode(ElementNode root)
        {
            EnsureArg.IsNotNull(root, nameof(root));

            if (root.IsBundleNode())
            {
                var entryResources = root.GetEntryResourceChildren();
                AnonymizeInternalResourceNodes(entryResources);
            }

            if (root.HasContainedNode())
            {
                var containedResources = root.GetContainedChildren();
                AnonymizeInternalResourceNodes(containedResources);
            }

            var resourceContext = ResourceAnonymizerContext.Create(root, _configurationManger);
            var resourceId      = root.GetNodeId();

            foreach (var rule in resourceContext.RuleList)
            {
                var pathCompileExpression = new FhirPathCompiler().Compile($"{rule.Path}");
                var matchedNodes          = pathCompileExpression(root, EvaluationContext.CreateDefault())
                                            .Cast <ElementNode>();

                _logger.LogDebug(rule.Type == AnonymizerRuleType.PathRule ?
                                 $"Path {rule.Source} matches {matchedNodes.Count()} nodes in resource ID {resourceId}." :
                                 $"Type {rule.Source} matches {matchedNodes.Count()} nodes with path {rule.Path} in resource ID {resourceId}.");

                foreach (var node in matchedNodes)
                {
                    AnonymizeChildNode(node, rule, resourceContext.PathSet, resourceId);
                }
            }

            return(root);
        }
示例#14
0
        public static object Scalar(this IElementNavigator input, string expression, EvaluationContext context = null, FhirPathCompiler compiler = null)
        {
            var evaluator = getCompiledExpression(expression, compiler);

            return(evaluator.Scalar(input, context ?? EvaluationContext.Default));
        }
示例#15
0
        public void ResolvePersonWithTwoNameSections()
        {
            FhirPathCompiler compiler = new FhirPathCompiler(CustomFhirPathFunctions.GetSymbolTable());

            Person person = new Person
            {
                Id         = "1",
                Identifier = new List <Identifier>
                {
                    new Identifier
                    {
                        System = "2.16.578.1.12.4.1.4.1",
                        Value  = "16027512345"
                    }
                },
                Name = new List <HumanName>
                {
                    new HumanName
                    {
                        Use    = HumanName.NameUse.Official,
                        Given  = new[] { "Kenneth", },
                        Family = "Myhra"
                    },
                    new HumanName
                    {
                        Use    = HumanName.NameUse.Old,
                        Given  = new[] { "Kenneth" },
                        Family = "AnnetEtternavn"
                    }
                },
                Telecom = new List <ContactPoint>
                {
                    new ContactPoint
                    {
                        Use    = ContactPoint.ContactPointUse.Mobile,
                        System = ContactPoint.ContactPointSystem.Phone,
                        Value  = "93228677"
                    },
                    new ContactPoint
                    {
                        Use    = ContactPoint.ContactPointUse.Home,
                        System = ContactPoint.ContactPointSystem.Phone,
                        Value  = "93228677"
                    },
                    new ContactPoint
                    {
                        Use    = ContactPoint.ContactPointUse.Home,
                        System = ContactPoint.ContactPointSystem.Email,
                        Value  = "*****@*****.**"
                    }
                },
                Address = new List <Address>
                {
                    new Address
                    {
                        Use        = Address.AddressUse.Home,
                        Line       = new [] { "Snipemyrveien 16" },
                        PostalCode = "1273",
                        City       = "Oslo",
                        Country    = "Norway"
                    }
                }
            };

            var personNavigator = new ScopedNavigator(new PocoNavigator(person));

            // Retrieve official name instance,
            // then concatenate given and family separating them by a white space
            IEnumerable <IElementNavigator> result = personNavigator.Select("name.where(use = 'official').select(given & ' ' & family)", compiler: compiler);

            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Kenneth Myhra", result.Single().Value);

            // Retrieve the distinct values of name and given in a collection for all name instances
            result = personNavigator.Select("(name.given | name.family)", compiler: compiler);
            Assert.AreEqual(3, result.Count());
            Trace.WriteLine(result.ToString());
            Assert.AreEqual("Kenneth", result.First().Value);
            Assert.AreEqual("Myhra", result.Skip(1).First().Value);
            Assert.AreEqual("AnnetEtternavn", result.Skip(2).First().Value);

            // Find identifier that represent FNR
            result = personNavigator.Select("Person.identifier.where(system = '2.16.578.1.12.4.1.4.1').value", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("16027512345", result.First().Value);

            // Find patient with family equal to 'Myhra'
            result = personNavigator.Select("Person.name.where(family = 'Myhra').family", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Myhra", result.First().Value);

            // Retrieve all name instances
            result = personNavigator.Select("Person.name.select(given.join(' ') & ' ' & family)", compiler: compiler);
            Assert.AreEqual(2, result.Count());
            var name = result.First().Value;

            Assert.AreEqual("Kenneth Myhra", name);
            name = result.Skip(1).First().Value;
            Assert.AreEqual("Kenneth AnnetEtternavn", name);

            // Retrieve first name instance
            result = personNavigator.Select("Person.name.select(given & ' ' & family).first()", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            name = result.SingleOrDefault().Value;
            Assert.IsNotNull(name);
            Assert.AreEqual("Kenneth Myhra", name);

            // Retrieve last name instance
            result = personNavigator.Select("Person.name.select(given & ' ' & family).last()", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            name = result.SingleOrDefault().Value;
            Assert.IsNotNull(name);
            Assert.AreEqual("Kenneth AnnetEtternavn", name);

            // Norwegian First name standard
            result = personNavigator.Select("Person.name.where(use = 'official').select(iif(given.count() > 1, given.take(count()-1), given).join(' '))", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Kenneth", result.Single().Value);

            // Norwegian middle name standard
            result = personNavigator.Select("Person.name.where(use = 'official').select(iif(given.count() > 1, given.last(), ''))", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("", result.Single().Value);

            // Family name / surname
            result = personNavigator.Select("Person.name.where(use = 'official').family", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Myhra", result.Single().Value);

            // Full name
            result = personNavigator.Select("Person.name.where(use = 'official').select(given.join(' ') & ' ' & family)", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Kenneth Myhra", result.Single().Value);

            // Phone number
            result = personNavigator.Select("Person.telecom.where(use = 'home' and system = 'phone').value");
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("93228677", result.Single().Value);

            // E-mail
            result = personNavigator.Select("Person.telecom.where(use = 'home' and system = 'email').value");
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("*****@*****.**", result.Single().Value);

            // Adresselinje 1
            result = personNavigator.Select("Person.address.where(use = 'home').line.first()");
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Snipemyrveien 16", result.Single().Value);

            // Adresselinje 2
            result = personNavigator.Select("Person.address.where(use = 'home').line.skip(1).first()");
            Assert.AreEqual(0, result.Count());

            // Adresselinje 3
            result = personNavigator.Select("Person.address.where(use = 'home').line.skip(2).first()");
            Assert.AreEqual(0, result.Count());

            // Postnummer
            result = personNavigator.Select("Person.address.where(use = 'home').postalCode");
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("1273", result.Single().Value);

            // Poststed
            result = personNavigator.Select("Person.address.where(use = 'home').city");
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Oslo", result.Single().Value);

            // Land
            result = personNavigator.Select("Person.address.where(use = 'home').country");
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Norway", result.Single().Value);

            // --------------

            // person2 has multiple given names.
            Person person2 = new Person
            {
                Id         = "1",
                Identifier = new List <Identifier>
                {
                    new Identifier
                    {
                        System = "2.16.578.1.12.4.1.4.1",
                        Value  = "16027512345"
                    }
                },
                Name = new List <HumanName>
                {
                    new HumanName
                    {
                        Use    = HumanName.NameUse.Official,
                        Given  = new[] { "Lars", "Kristoffer", "Ulstein" },
                        Family = "Jørgensen"
                    }
                }
            };

            var personNavigator2 = new ScopedNavigator(new PocoNavigator(person2));

            // Norwegian First name standard
            result = personNavigator2.Select("Person.name.where(use = 'official').select(iif(given.count() > 1, given.take(count()-1), given).join(' '))", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Lars Kristoffer", result.Single().Value);

            // Norwegian middle name standard
            result = personNavigator2.Select("Person.name.where(use = 'official').select(iif(given.count() > 1, given.last(), ''))", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Ulstein", result.Single().Value);

            // Family name / surname
            result = personNavigator2.Select("Person.name.where(use = 'official').family", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Jørgensen", result.Single().Value);

            // Full name
            result = personNavigator2.Select("Person.name.where(use = 'official').select(given.join(' ') & ' ' & family)", compiler: compiler);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual("Lars Kristoffer Ulstein Jørgensen", result.Single().Value);
        }
示例#16
0
 public PatchService()
 {
     _compiler = new FhirPathCompiler();
 }
示例#17
0
        public static IEnumerable <IElementNavigator> Select(this IElementNavigator input, string expression, EvaluationContext context = null, FhirPathCompiler compiler = null)
        {
            var evaluator = getCompiledExpression(expression, compiler);

            return(evaluator(input, context ?? EvaluationContext.Default));
        }
        private static CompiledExpression Compile(string expression)
        {
            var compiler = new FhirPathCompiler();

            return(compiler.Compile(expression));
        }
        public void Validate(AnonymizerConfiguration config)
        {
            if (string.IsNullOrEmpty(config.FhirVersion))
            {
                _logger.LogWarning($"Version is not specified in configuration file.");
            }
            else if (!string.Equals(Constants.SupportedVersion, config.FhirVersion, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new AnonymizerConfigurationErrorsException($"Configuration of fhirVersion {config.FhirVersion} is not supported. Expected fhirVersion: {Constants.SupportedVersion}");
            }

            if (config.FhirPathRules == null)
            {
                throw new AnonymizerConfigurationErrorsException("The configuration is invalid, please specify any fhirPathRules");
            }

            FhirPathCompiler compiler = new FhirPathCompiler();
            var supportedMethods      = Enum.GetNames(typeof(AnonymizerMethod)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);

            foreach (var rule in config.FhirPathRules)
            {
                if (!rule.ContainsKey(Constants.PathKey) || !rule.ContainsKey(Constants.MethodKey))
                {
                    throw new AnonymizerConfigurationErrorsException("Missing path or method in Fhir path rule config.");
                }

                // Grammar check on FHIR path
                try
                {
                    compiler.Compile(rule[Constants.PathKey].ToString());
                }
                catch (Exception ex)
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid FHIR path {rule[Constants.PathKey]}", ex);
                }

                // Method validate
                string method = rule[Constants.MethodKey].ToString();
                if (!supportedMethods.Contains(method))
                {
                    throw new AnonymizerConfigurationErrorsException($"Anonymization method {method} not supported.");
                }

                // Should provide replacement value for substitute rule
                if (string.Equals(method, AnonymizerMethod.Substitute.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    SubstituteSetting.ValidateRuleSettings(rule);
                }

                if (string.Equals(method, AnonymizerMethod.Perturb.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    PerturbSetting.ValidateRuleSettings(rule);
                }
                if (string.Equals(method, AnonymizerMethod.Generalize.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    GeneralizeSetting.ValidateRuleSettings(rule);
                }
            }

            // Check AES key size is valid (16, 24 or 32 bytes).
            if (!string.IsNullOrEmpty(config.ParameterConfiguration?.EncryptKey))
            {
                using Aes aes = Aes.Create();
                var encryptKeySize = Encoding.UTF8.GetByteCount(config.ParameterConfiguration.EncryptKey) * 8;
                if (!IsValidKeySize(encryptKeySize, aes.LegalKeySizes))
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid encrypt key size : {encryptKeySize} bits! Please provide key sizes of 128, 192 or 256 bits.");
                }
            }
        }
 public CustomNavigator(IElementNavigator wrapped, FhirPathCompiler compiler) : base(wrapped)
 {
     _compiler = compiler;
 }