/// <summary>Initializes a new instance of the <see cref="FhirCodeSystem"/> class.</summary> /// <exception cref="ArgumentNullException">Thrown when one or more required arguments are null.</exception> /// <param name="name"> The name.</param> /// <param name="id"> The identifier.</param> /// <param name="version"> The version.</param> /// <param name="title"> The title.</param> /// <param name="url"> The URL.</param> /// <param name="standardStatus">The standard status.</param> /// <param name="description"> The description.</param> /// <param name="content"> The content.</param> /// <param name="rootConcept"> The root concept.</param> /// <param name="conceptLookup"> The concept lookup.</param> public FhirCodeSystem( string name, string id, string version, string title, string url, string standardStatus, string description, string content, FhirConceptTreeNode rootConcept, Dictionary <string, FhirConceptTreeNode> conceptLookup) { if (url == null) { throw new ArgumentNullException(nameof(url)); } Name = name; Id = id; Version = version; Title = title; URL = url; StandardStatus = standardStatus; Description = description; Content = content; _rootConcept = rootConcept; _conceptLookup = conceptLookup; }
/// <summary>Adds a node.</summary> /// <param name="concept">The concept.</param> /// <returns>A FhirConceptTreeNode.</returns> public FhirConceptTreeNode AddChild(FhirConcept concept) { if (concept == null) { return(null); } if (_children.ContainsKey(concept.Code)) { return(_children[concept.Code]); } FhirConceptTreeNode node = new FhirConceptTreeNode(concept, this); _children.Add(concept.Code, node); return(node); }
/// <summary>Initializes a new instance of the <see cref="FhirConceptTreeNode"/> class.</summary> /// <param name="concept">The concept.</param> /// <param name="parent"> The parent.</param> public FhirConceptTreeNode(FhirConcept concept, FhirConceptTreeNode parent) { _concept = concept; _children = new Dictionary <string, FhirConceptTreeNode>(); _parent = parent; }
/// <summary>Adds from node.</summary> /// <param name="values"> [in,out] The values.</param> /// <param name="node"> The node.</param> /// <param name="includeSelf"> True to include, false to exclude the self.</param> /// <param name="includeChildren"> True to include, false to exclude the children.</param> /// <param name="includeParents"> True to include, false to exclude the parents.</param> /// <param name="exclusionKey"> The exclusion key.</param> /// <param name="regex"> The RegEx.</param> /// <param name="inclusionSet"> Set the inclusion belongs to.</param> /// <param name="exclusionSet"> Set the exclusion belongs to.</param> /// <param name="maxRecursions"> (Optional) The maximum recursions (-1 for no limit).</param> /// <param name="filterProperties">(Optional) The include properties.</param> private static void AddFromNode( ref Dictionary <string, FhirConcept> values, FhirConceptTreeNode node, bool includeSelf, bool includeChildren, bool includeParents, string exclusionKey, Regex regex, HashSet <string> inclusionSet, HashSet <string> exclusionSet, int maxRecursions = -1, List <KeyValuePair <string, string> > filterProperties = null) { if ((!string.IsNullOrEmpty(exclusionKey)) && (node.Concept != null) && (node.Concept.Code == exclusionKey)) { return; } if (includeSelf && (node.Concept != null) && (!values.ContainsKey(node.Concept.Code)) && ((regex == null) || regex.IsMatch(node.Concept.Code)) && ((inclusionSet == null) || inclusionSet.Contains(node.Concept.Code)) && ((exclusionSet == null) || (!exclusionSet.Contains(node.Concept.Code)))) { string key = node.Concept.Key(); if (!values.ContainsKey(key)) { if ((filterProperties != null) && (filterProperties.Count > 0)) { if (node.Concept.MatchesProperties(filterProperties)) { values.Add(key, node.Concept); } } else { values.Add(key, node.Concept); } } } if (includeChildren && (node.Children != null) && (maxRecursions != 0)) { if (maxRecursions > 0) { maxRecursions--; } foreach (FhirConceptTreeNode child in node.Children.Values) { AddFromNode( ref values, child, true, true, false, exclusionKey, regex, inclusionSet, exclusionSet, maxRecursions, filterProperties); } } if (includeParents && (node.Parent != null) && (maxRecursions != 0)) { if (maxRecursions > 0) { maxRecursions--; } AddFromNode( ref values, node.Parent, true, false, true, exclusionKey, regex, inclusionSet, exclusionSet, maxRecursions, filterProperties); } }
/// <summary>Adds a filtered concepts.</summary> /// <exception cref="ArgumentNullException">Thrown when one or more required arguments are null.</exception> /// <param name="values"> [in,out] The values.</param> /// <param name="codeSystem">The code system.</param> /// <param name="filters"> Specifies the filters.</param> /// <param name="include"> True to include, false to exclude.</param> /// <param name="exclude"> True to exclude, false to include.</param> private static void ApplyFilteredConcepts( ref Dictionary <string, FhirConcept> values, FhirCodeSystem codeSystem, List <FhirValueSetFilter> filters, bool include, bool exclude) { if (codeSystem == null) { throw new ArgumentNullException(nameof(codeSystem)); } if ((filters == null) || (filters.Count == 0)) { throw new ArgumentNullException(nameof(filters)); } if (include && exclude) { #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new Exception("Cannot include and exclude the same filters!"); #pragma warning restore CA1303 // Do not pass literals as localized parameters } if ((!include) && (!exclude)) { #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new Exception("Must either include or exclude for filters!"); #pragma warning restore CA1303 // Do not pass literals as localized parameters } string startingCode = string.Empty; bool includeSelf = false; bool includeChildren = false; bool includeParents = false; string exclusionKey = string.Empty; Regex regex = null; HashSet <string> inclusionSet = null; HashSet <string> exclusionSet = null; int maxRecusrions = -1; List <KeyValuePair <string, string> > filterProperties = new List <KeyValuePair <string, string> >(); foreach (FhirValueSetFilter filter in filters) { string filterKey = $"{filter.Property}:{filter.Operation}"; switch (filterKey) { case "concept:=": startingCode = filter.Value; includeSelf = true; includeChildren = false; includeParents = false; break; case "concept:is-a": startingCode = filter.Value; includeSelf = true; includeChildren = true; includeParents = false; break; case "concept:descendent-of": startingCode = filter.Value; includeSelf = false; includeChildren = true; includeParents = false; break; case "concept:is-not-a": exclusionKey = filter.Value; break; case "concept:regex": regex = new Regex(filter.Value); break; case "concept:in": inclusionSet = new HashSet <string>(); string[] inculsions = filter.Value.Split(','); foreach (string value in inculsions) { inclusionSet.Add(value); } break; case "concept:not-in": exclusionSet = new HashSet <string>(); string[] exclusions = filter.Value.Split(','); foreach (string value in exclusions) { exclusionSet.Add(value); } break; case "concept:generalizes": startingCode = filter.Value; includeSelf = true; includeChildren = false; includeParents = true; break; case "parent:=": startingCode = filter.Value; includeSelf = false; includeChildren = true; includeParents = false; maxRecusrions = 1; break; case "child:=": startingCode = filter.Value; includeSelf = false; includeChildren = false; includeParents = true; maxRecusrions = 1; break; // ignore these case "acme-plasma:=": return; case "concept:exists": default: if (filter.Operation == "=") { filterProperties.Add(new KeyValuePair <string, string>(filter.Property, filter.Value)); includeSelf = true; includeChildren = true; includeParents = false; continue; } throw new NotImplementedException($"Unhandled filter: {filterKey}"); } } FhirConceptTreeNode startingNode = codeSystem.RootConcept; if ((!string.IsNullOrEmpty(startingCode)) && codeSystem.ContainsConcept(startingCode)) { startingNode = codeSystem[startingCode]; } if (include) { AddFromNode( ref values, startingNode, includeSelf, includeChildren, includeParents, exclusionKey, regex, inclusionSet, exclusionSet, maxRecusrions, filterProperties); } if (exclude) { RemoveFromNode( ref values, startingNode, includeSelf, includeChildren, includeParents, exclusionKey, regex, inclusionSet, exclusionSet, maxRecusrions, filterProperties); } }
/// <summary>Removes from node.</summary> /// <param name="values"> [in,out] The values.</param> /// <param name="node"> The node.</param> /// <param name="includeSelf"> True to include, false to exclude the self.</param> /// <param name="includeChildren">True to include, false to exclude the children.</param> /// <param name="includeParents"> True to include, false to exclude the parents.</param> /// <param name="exclusionKey"> The exclusion key.</param> /// <param name="regex"> The RegEx.</param> /// <param name="inclusionSet"> Set the inclusion belongs to.</param> /// <param name="exclusionSet"> Set the exclusion belongs to.</param> /// <param name="maxRecursions"> (Optional) The maximum recursions (-1 for no limit).</param> private static void RemoveFromNode( ref Dictionary <string, FhirConcept> values, FhirConceptTreeNode node, bool includeSelf, bool includeChildren, bool includeParents, string exclusionKey, Regex regex, HashSet <string> inclusionSet, HashSet <string> exclusionSet, int maxRecursions = -1) { if ((!string.IsNullOrEmpty(exclusionKey)) && (node.Concept.Code == exclusionKey)) { return; } if (includeSelf && (!values.ContainsKey(node.Concept.Code)) && ((regex == null) || regex.IsMatch(node.Concept.Code)) && ((inclusionSet == null) || inclusionSet.Contains(node.Concept.Code)) && ((exclusionSet == null) || (!exclusionSet.Contains(node.Concept.Code)))) { if (values.ContainsKey(node.Concept.Code)) { values.Remove(node.Concept.Code); } } if (includeChildren && (node.Children != null) && (maxRecursions != 0)) { if (maxRecursions > 0) { maxRecursions--; } foreach (FhirConceptTreeNode child in node.Children.Values) { RemoveFromNode( ref values, child, true, true, false, exclusionKey, regex, inclusionSet, exclusionSet, maxRecursions); } } if (includeParents && (node.Parent != null) && (maxRecursions != 0)) { if (maxRecursions > 0) { maxRecursions--; } RemoveFromNode( ref values, node.Parent, true, false, true, exclusionKey, regex, inclusionSet, exclusionSet, maxRecursions); } }