예제 #1
0
        // Remove null children of current node, and return true => current node is null
        public static bool RemoveNullChildren(this ElementNode node)
        {
            if (node == null)
            {
                return(true);
            }

            var children = node.Children().Cast <ElementNode>().ToList();

            foreach (var child in children)
            {
                // Remove child if it is null => return true
                if (RemoveNullChildren(child))
                {
                    node.Remove(child);
                }
            }

            bool currentNodeIsEmpty        = !node.Children().Any() && node.Value == null;
            bool currentNodeIsFhirResource = node.IsFhirResource();

            if (currentNodeIsEmpty && !currentNodeIsFhirResource)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #2
0
 public void AccessViaIndexers()
 {
     Assert.Equal("Patient.active[0].extension[1].value[0]", patient["active"][0]["extension"][1]["value"][0].Location);
     Assert.Equal("Patient.active[0].extension[1].value[0]", patient["active"]["extension"][1]["value"].Single().Location);
     Assert.Equal("Patient.active[0].extension[0].value[0]", patient.Children("active").First()
                  .Children("extension").First()
                  .Children("value").First().Location);
     Assert.Equal("Patient.active[0].extension[0].value[0]", patient.Children("active")
                  .Children("extension").First()
                  .Children("value").Single().Location);
 }
예제 #3
0
        public ProcessResult Process(ElementNode node, ProcessContext context = null, Dictionary <string, object> settings = null)
        {
            EnsureArg.IsNotNull(node);
            EnsureArg.IsNotNull(context?.VisitedNodes);
            EnsureArg.IsNotNull(settings);

            var result = new ProcessResult();

            ElementNode valueNode = null;

            if (s_primitiveValueTypeNames.Contains(node.InstanceType, StringComparer.InvariantCultureIgnoreCase))
            {
                valueNode = node;
            }
            else if (s_quantityTypeNames.Contains(node.InstanceType, StringComparer.InvariantCultureIgnoreCase))
            {
                valueNode = node.Children(Constants.ValueNodeName).Cast <ElementNode>().FirstOrDefault();
            }

            // Perturb will not happen if value node is empty or visited.
            if (valueNode?.Value == null || context.VisitedNodes.Contains(valueNode))
            {
                return(result);
            }

            var perturbSetting = PerturbSetting.CreateFromRuleSettings(settings);

            AddNoise(valueNode, perturbSetting);
            context.VisitedNodes.UnionWith(node.Descendants().Cast <ElementNode>());
            result.AddProcessRecord(AnonymizationOperations.Perturb, node);
            return(result);
        }
예제 #4
0
        public ProcessResult ProcessNodeRecursive(ElementNode node, IAnonymizerProcessor processor,
                                                  ProcessContext context, Dictionary <string, object> settings)
        {
            var result = new ProcessResult();

            if (_visitedNodes.Contains(node))
            {
                return(result);
            }

            result = processor.Process(node, context, settings);
            _visitedNodes.Add(node);

            foreach (var child in node.Children().CastElementNodes())
            {
                if (child.IsFhirResource())
                {
                    continue;
                }

                result.Update(ProcessNodeRecursive(child, processor, context, settings));
            }

            return(result);
        }
        private static void TransformTypeRulesToPathRules(ElementNode node, Dictionary <string, string> typeRules, List <AnonymizerRule> rules, HashSet <string> rulePaths)
        {
            if (node.IsContainedNode() || node.IsEntryNode())
            {
                return;
            }

            string path = node.GetFhirPath();

            if (rulePaths.Contains(path))
            {
                return;
            }

            if (typeRules.ContainsKey(node.InstanceType))
            {
                var rule = new AnonymizerRule(path, typeRules[node.InstanceType], AnonymizerRuleType.TypeRule, node.InstanceType);

                rules.Add(rule);
                rulePaths.Add(rule.Path);
            }

            var children = node.Children().Cast <ElementNode>();

            foreach (var child in children)
            {
                TransformTypeRulesToPathRules(child, typeRules, rules, rulePaths);
            }
        }
예제 #6
0
 // Post-process to mark all substituted children nodes as visited
 private void MarkSubstitutedFragmentAsVisited(ElementNode node, HashSet <ElementNode> visitedNodes)
 {
     visitedNodes.Add(node);
     foreach (var child in node.Children().Cast <ElementNode>())
     {
         MarkSubstitutedFragmentAsVisited(child, visitedNodes);
     }
 }
예제 #7
0
 public static List <ElementNode> GetEntryResourceChildren(this ElementNode node)
 {
     return(node?.Children(s_entryNodeName)
            .Select(entry => entry?.Children(s_resourceNodeName).FirstOrDefault())
            .Where(resource => resource != null)
            .Cast <ElementNode>()
            .ToList());
 }
예제 #8
0
        public static void RemoveNullChildren(this ElementNode node)
        {
            if (node == null)
            {
                return;
            }

            var children = node.Children().Cast <ElementNode>().ToList();

            foreach (var child in children)
            {
                RemoveNullChildren(child);
            }

            if (!node.Children().Any() && node.Value == null && !Enum.TryParse <ResourceType>(node.InstanceType, true, out _))
            {
                node.Parent.Remove(node);
                return;
            }
        }
        private static string TryGetResourceId(ElementNode node)
        {
            while (node.Parent != null)
            {
                node = node.Parent;
            }

            var id = node.Children("id").FirstOrDefault();

            return(id != null?id.Value.ToString() : string.Empty);
        }
예제 #10
0
        public static void Accept(this ElementNode node, AbstractElementNodeVisitor visitor)
        {
            bool shouldVisitChild = visitor.Visit(node);

            if (shouldVisitChild)
            {
                foreach (var child in node.Children().Cast <ElementNode>())
                {
                    child.Accept(visitor);
                }
            }

            visitor.EndVisit(node);
        }
        public static IEnumerable <ElementNode> ResourceDescendantsWithoutSubResource(this ElementNode node)
        {
            foreach (var child in node.Children().Cast <ElementNode>())
            {
                // Skip sub resources in bundle entry and contained list
                if (child.IsFhirResource())
                {
                    continue;
                }

                yield return(child);

                foreach (var n in child.ResourceDescendantsWithoutSubResource())
                {
                    yield return(n);
                }
            }
        }
예제 #12
0
        // To keep consistent anonymization changes made by preceding rules, we should figure out whether a node can be removed during substitution
        private bool GenerateKeepNodeSetForSubstitution(ElementNode node, HashSet <ElementNode> visitedNodes, HashSet <ElementNode> keepNodes)
        {
            var shouldKeep = false;

            // If a child (no matter how deep) has been modified, this node should be kept
            foreach (var child in node.Children().Cast <ElementNode>())
            {
                shouldKeep |= GenerateKeepNodeSetForSubstitution(child, visitedNodes, keepNodes);
            }

            // If this node its self has been modified, it should be kept
            if (shouldKeep || visitedNodes.Contains(node))
            {
                keepNodes.Add(node);
                return(true);
            }

            return(shouldKeep);
        }
        private void AnonymizeChildNode(ElementNode node, string method, HashSet <string> rulePathSet)
        {
            method = method.ToUpperInvariant();

            if (node.Value != null && _processors.ContainsKey(method))
            {
                _processors[method].Process(node);
            }

            var children = node.Children().Cast <ElementNode>();

            foreach (var child in children)
            {
                if (!rulePathSet.Contains(child.GetFhirPath()))
                {
                    AnonymizeChildNode(child, method, rulePathSet);
                }
            }
        }
예제 #14
0
        private void AnonymizeChildNode(ElementNode node, AnonymizerRule rule, HashSet <string> rulePathSet, string resourceId)
        {
            var method = rule.Method.ToUpperInvariant();

            if (node.Value != null && _processors.ContainsKey(method))
            {
                _processors[method].Process(node);
                _logger.LogDebug($"{node.GetFhirPath()} in resource ID {resourceId} is applied {method} due to rule \"{rule.Source}:{rule.Method}\"");
            }

            var children = node.Children().Cast <ElementNode>();

            foreach (var child in children)
            {
                if (!rulePathSet.Contains(child.GetFhirPath()))
                {
                    AnonymizeChildNode(child, rule, rulePathSet, resourceId);
                }
            }
        }
예제 #15
0
        public static void RemoveEmptyNodes(this ElementNode node)
        {
            if (node == null)
            {
                return;
            }

            var children = node.Children().ToList();

            foreach (var child in children)
            {
                var elementNodeChild = (ElementNode)child;

                // Remove empty nodes recursively
                RemoveEmptyNodes(elementNodeChild);

                if (IsEmptyNode(elementNodeChild))
                {
                    node.Remove(elementNodeChild);
                }
            }
        }
예제 #16
0
        public ProcessResult ProcessNodeRecursive(ElementNode node, IAnonymizerProcessor processor, HashSet <ElementNode> visitedNodes)
        {
            ProcessResult result = new ProcessResult();

            if (visitedNodes.Contains(node))
            {
                return(result);
            }

            result = processor.Process(node);
            visitedNodes.Add(node);

            foreach (var child in node.Children().Cast <ElementNode>())
            {
                if (child.IsFhirResource())
                {
                    continue;
                }

                result.Update(ProcessNodeRecursive(child, processor, visitedNodes));
            }

            return(result);
        }
 public static ElementNode GetMeta(this ElementNode node)
 {
     return(node?.Children("meta").Cast <ElementNode>().FirstOrDefault());
 }
        public static string GetNodeId(this ElementNode node)
        {
            var id = node.Children("id").FirstOrDefault();

            return(id?.Value?.ToString() ?? string.Empty);
        }
 public static bool HasContainedNode(this ElementNode node)
 {
     return(node != null && node.Children(Constants.ContainedNodeName).Any());
 }
예제 #20
0
 public static List <ElementNode> GetContainedChildren(this ElementNode node)
 {
     return(node?.Children(s_containedNodeName).Cast <ElementNode>().ToList());
 }
예제 #21
0
        private ProcessResult SubstituteNode(ElementNode node, ElementNode replacementNode, HashSet <ElementNode> visitedNodes, HashSet <ElementNode> keepNodes)
        {
            var processResult = new ProcessResult();

            if (node == null || replacementNode == null || visitedNodes.Contains(node))
            {
                return(processResult);
            }

            // children names to replace, multiple to multiple replacement
            var replaceChildrenNames = replacementNode.Children().Select(element => element.Name).ToHashSet();

            foreach (var name in replaceChildrenNames)
            {
                var children       = node.Children(name).Cast <ElementNode>().ToList();
                var targetChildren = replacementNode.Children(name).Cast <ElementNode>().ToList();

                int i = 0;
                foreach (var child in children)
                {
                    if (visitedNodes.Contains(child))
                    {
                        // Skip replacement if child already processed before.
                        i++;
                        continue;
                    }
                    else if (i < targetChildren.Count)
                    {
                        // We still have target nodes, do replacement
                        SubstituteNode(child, targetChildren[i++], visitedNodes, keepNodes);
                    }
                    else if (keepNodes.Contains(child))
                    {
                        // Substitute with an empty node when no target node available but we need to keep this node
                        SubstituteNode(child, GetDummyNode(), visitedNodes, keepNodes);
                    }
                    else
                    {
                        // Remove source node when no target node available and we don't need to keep the source node
                        node.Remove(child);
                    }
                }

                while (i < targetChildren.Count)
                {
                    // Add extra target nodes, create a new copy before adding
                    node.Add(s_provider, ElementNode.FromElement(targetChildren[i++]));
                }
            }

            // children nodes not presented in replacement value, we need either remove or keep a dummy copy
            var nonReplacementChildren = node.Children()
                                         .Where(element => !replaceChildrenNames.Contains(element.Name))
                                         .Cast <ElementNode>().ToList();

            foreach (var child in nonReplacementChildren)
            {
                if (visitedNodes.Contains(child))
                {
                    continue;
                }
                else if (keepNodes.Contains(child))
                {
                    SubstituteNode(child, GetDummyNode(), visitedNodes, keepNodes);
                }
                else
                {
                    node.Remove(child);
                }
            }

            node.Value = replacementNode.Value;
            processResult.AddProcessRecord(AnonymizationOperations.Substitute, node);
            return(processResult);
        }