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); } }
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); }
public void TestTreeVisualizerVisitor() { var compiler = new FhirPathCompiler(); var expr = compiler.Parse("doSomething('ha!', 4, {}, $this, somethingElse(true))"); var result = expr.Dump(); Debug.WriteLine(result); }
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()); }
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(); }
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); } }
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); } }
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); }
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); }
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)); }
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); }
public PatchService() { _compiler = new FhirPathCompiler(); }
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; }