Ejemplo n.º 1
0
#pragma warning disable CS0618 // Type or member is obsolete
        private static void ElementNavPerformance(IElementNavigator nav)
#pragma warning restore CS0618 // Type or member is obsolete
        {
            // run extraction once to allow for caching
            extract();

            //System.Threading.Thread.Sleep(20000);

            var sw = new Stopwatch();

            sw.Start();
            for (var i = 0; i < 5_000; i++)
            {
                extract();
            }
            sw.Stop();

            Debug.WriteLine($"Navigating took {sw.ElapsedMilliseconds / 5 } micros");

            void extract()
            {
                var usual = nav.Children("identifier").First().Children("use").First().Value;
                var phone = nav.Children("telecom").First().Children("system").First().Value;
                var prefs = nav.Children("communication").Where(c => c.Children("preferred").Any(pr => pr.Value is string s && s == "true")).Count();
                var link  = nav.Children("link").Children("other").Children("reference");
            }
        }
 public static ResourceReference ParseResourceReference(this IElementNavigator instance)
 {
     return(new ResourceReference()
     {
         Reference = instance.Children("reference").GetString(),
         Display = instance.Children("display").GetString()
     });
 }
 public static CodeableConcept ParseCodeableConcept(this IElementNavigator instance)
 {
     return(new CodeableConcept()
     {
         Coding =
             instance.Children("coding").Select(codingNav => codingNav.ParseCoding()).ToList(),
         Text = instance.Children("text").GetString()
     });
 }
 public static Coding ParseCoding(this IElementNavigator instance)
 {
     return(new Coding()
     {
         System = instance.Children("system").GetString(),
         Version = instance.Children("version").GetString(),
         Code = instance.Children("code").GetString(),
         Display = instance.Children("display").GetString(),
         UserSelected = instance.Children("userSelected").SingleOrDefault()?.Value as bool?
     });
 }
Ejemplo n.º 5
0
 public static IEnumerable <Scope> HarvestResource(IElementNavigator instance)
 {
     return(instance.Children("contained")
            .Select(child =>
                    new Scope(child,
                              "#" + getStringValue(child.Children("id").FirstOrDefault()))));
 }
        public static bool IsExactlyEqualTo(this IElementNavigator left, IElementNavigator right)
        {
            if (left == null && right == null)
            {
                return(true);
            }
            if (left == null || right == null)
            {
                return(false);
            }

            if (!ValueEquality(left.Value, right.Value))
            {
                return(false);
            }

            // Compare the children.
            var childrenL = left.Children();
            var childrenR = right.Children();

            if (childrenL.Count() != childrenR.Count())
            {
                return(false);
            }

            return(childrenL.Zip(childrenR,
                                 (childL, childR) => childL.Name == childR.Name && childL.IsExactlyEqualTo(childR)).All(t => t));
        }
Ejemplo n.º 7
0
        public static IEnumerable <IElementNavigator> Navigate(this IElementNavigator nav, string name)
        {
            if (char.IsUpper(name[0]))
            {
                if (!char.IsUpper(nav.Name[0]))
                {
                    throw Error.InvalidOperation("Resource type name may only appear at the root of a document");
                }

                // If we are at a resource, we should match a path that is possibly not rooted in the resource
                // (e.g. doing "name.family" on a Patient is equivalent to "Patient.name.family")
                if (nav.Type == name)
                {
                    return(new List <IElementNavigator>()
                    {
                        nav
                    });
                }
                else
                {
                    return(Enumerable.Empty <IElementNavigator>());
                }
            }
            else
            {
                return(nav.Children(name));
            }
        }
Ejemplo n.º 8
0
        public static IEnumerable <IElementNavigator> Navigate(this IElementNavigator nav, string name)
        {
            if (char.IsUpper(name[0]))
            {
                if (!char.IsUpper(nav.Name[0]))
                {
                    throw Error.InvalidOperation("Resource type name may only appear at the root of a document");
                }

                // If we are at a resource, we should match a path that is possibly not rooted in the resource
                // (e.g. doing "name.family" on a Patient is equivalent to "Patient.name.family")
                // Also we do some poor polymorphism here: Resource.meta.lastUpdated is also allowed.
                var baseClasses = new[] { "Resource", "DomainResource" };
                if (nav.Type == name || baseClasses.Contains(name))
                {
                    return(new List <IElementNavigator>()
                    {
                        nav
                    });
                }
                else
                {
                    return(Enumerable.Empty <IElementNavigator>());
                }
            }
            else
            {
                return(nav.Children(name));
            }
        }
        public static ComparisonResult IsEqualTo(this IElementNavigator expected, IElementNavigator actual)
        {
            if (!namesEqual(expected.Name, actual.Name))
            {
                return(ComparisonResult.Fail(actual.Location, $"name: was '{actual.Name}', expected '{expected.Name}'"));
            }
            if (!valuesEqual(expected.Value, actual.Value))
            {
                return(ComparisonResult.Fail(actual.Location, $"value: was '{actual.Value}', expected '{expected.Value}'"));
            }

            // Allow the expected navigator to have more type info than the actual navigator
            if (expected.Type != actual.Type && actual.Type != null)
            {
                return(ComparisonResult.Fail(actual.Location, $"type: was '{actual.Type}', expected '{expected.Type}'"));
            }
            if (expected.Location != actual.Location)
            {
                ComparisonResult.Fail(actual.Location, $"location: was '{actual.Location}', expected '{expected.Location}'");
            }

            // Ignore ordering (only relevant to xml)
            var childrenExp    = expected.Children().OrderBy(e => e.Name);
            var childrenActual = actual.Children().OrderBy(e => e.Name).GetEnumerator();

            // Don't compare lengths, as this would require complete enumeration of both collections
            // just enumerate through the lists, comparing each item as they go.
            // first fail (or list end) will drop out.
            foreach (var exp in childrenExp)
            {
                if (!childrenActual.MoveNext())
                {
                    ComparisonResult.Fail(actual.Location, $"number of children was different");
                }

                var result = exp.IsEqualTo(childrenActual.Current);
                if (!result.Success)
                {
                    return(result);
                }
            }
            if (childrenActual.MoveNext())
            {
                ComparisonResult.Fail(actual.Location, $"number of children was different");
            }

            return(ComparisonResult.OK);

            bool valuesEqual(object e, object a)
            {
                string eVal = e != null?PrimitiveTypeConverter.ConvertTo <string>(e) : null;

                string aVal = a != null?PrimitiveTypeConverter.ConvertTo <string>(a) : null;

                return(eVal == aVal);
            }

            bool namesEqual(string e, string a) => e == a || (a != null && e != null && (a.StartsWith(e)));
        }
 public static void Visit(this IElementNavigator navigator, Action <IElementNavigator> visitor)
 {
     visitor(navigator);
     foreach (var child in navigator.Children())
     {
         Visit(child, visitor);
     }
 }
 private static void visit(this IElementNavigator navigator, Action <int, IElementNavigator> visitor, int depth = 0)
 {
     visitor(depth, navigator);
     foreach (var child in navigator.Children())
     {
         visit(child, visitor, depth + 1);
     }
 }
Ejemplo n.º 12
0
        public string Id()
        {
            if (_cache.Id == null)
            {
                _cache.Id = AtResource ? "#" + _wrapped.Children("id").FirstOrDefault()?.Value as string : null;
            }

            return(_cache.Id);
        }
Ejemplo n.º 13
0
 public static IEnumerable <Scope> HarvestBundle(IElementNavigator instance)
 {
     return(instance.Children("entry")
            .SelectMany(entry =>
                        entry.Children("resource").Take(1)
                        .Select(res =>
                                new Scope(res,
                                          getStringValue(entry.Children("fullUrl").FirstOrDefault())))));
 }
Ejemplo n.º 14
0
        public ProfilePreprocessor(Func <string, StructureDefinition> profileResolver, Action <StructureDefinition> snapshotGenerator,
                                   IElementNavigator instance, string declaredTypeProfile,
                                   IEnumerable <StructureDefinition> additionalProfiles, IEnumerable <string> additionalCanonicals)
        {
            _profileResolver   = profileResolver;
            _snapshotGenerator = snapshotGenerator;
            _path = instance.Location;

            _profiles = new ProfileAssertion(_path, _profileResolver);

            if (instance.Type != null)
            {
                _profiles.SetInstanceType(ModelInfo.CanonicalUriForFhirCoreType(instance.Type));
            }
            if (declaredTypeProfile != null)
            {
                _profiles.SetDeclaredType(declaredTypeProfile);
            }

            // This is only for resources, but I don't bother checking, since this will return empty anyway
            _profiles.AddStatedProfile(instance.Children("meta").Children("profile").Select(p => p.Value).Cast <string>());

            //Almost identically, extensions can declare adherance to a profile using the 'url' attribute
            if (declaredTypeProfile == ModelInfo.CanonicalUriForFhirCoreType(FHIRDefinedType.Extension))
            {
                var urlDeclaration = instance.Children("url").FirstOrDefault()?.Value as string;

                if (urlDeclaration != null && urlDeclaration.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
                {
                    _profiles.AddStatedProfile(urlDeclaration);
                }
            }

            if (additionalProfiles != null)
            {
                _profiles.AddStatedProfile(additionalProfiles);
            }
            if (additionalCanonicals != null)
            {
                _profiles.AddStatedProfile(additionalCanonicals);
            }
        }
        public static IEnumerable <IElementNavigator> Descendants(this IElementNavigator navigator)
        {
            foreach (var child in navigator.Children())
            {
                yield return(child);

                foreach (var grandchild in child.Descendants())
                {
                    yield return(grandchild);
                }
            }
        }
        public static ComparisonResult IsEqualTo(this IElementNavigator expected, IElementNavigator actual)
        {
            if (!valuesEqual(expected.Value, actual.Value))
            {
                return(ComparisonResult.Fail(actual.Location, $"value: was '{actual.Value}', expected '{expected.Value}'"));
            }
            if (!namesEqual(expected.Name, actual.Name))
            {
                return(ComparisonResult.Fail(actual.Location, $"name: was '{actual.Name}', expected '{expected.Name}'"));
            }

            // Allow the expected navigator to have more type info than the actual navigator
            if (expected.Type != actual.Type && actual.Type != null)
            {
                return(ComparisonResult.Fail(actual.Location, $"type: was '{actual.Type}', expected '{expected.Type}'"));
            }
            if (expected.Location != actual.Location)
            {
                ComparisonResult.Fail(actual.Location, $"location: was '{actual.Location}', expected '{expected.Location}'");
            }

            // Ignore ordering (only relevant to xml)
            var childrenExp    = expected.Children().OrderBy(e => e.Name).ToArray();
            var childrenActual = actual.Children().OrderBy(e => e.Name).ToArray();

            if (childrenExp.Length != childrenActual.Length)
            {
                ComparisonResult.Fail(actual.Location, $"number of children was {childrenActual.Length}, expected {childrenExp.Length}");
            }

            for (var index = 0; index < childrenExp.Length; index++)
            {
                var result = childrenExp[index].IsEqualTo(childrenActual[index]);
                if (!result.Success)
                {
                    return(result);
                }
            }

            return(ComparisonResult.OK);

            bool valuesEqual(object e, object a)
            {
                string eVal = e != null?PrimitiveTypeConverter.ConvertTo <string>(e) : null;

                string aVal = a != null?PrimitiveTypeConverter.ConvertTo <string>(a) : null;

                return(eVal == aVal);
            }

            bool namesEqual(string e, string a) => e == a || (a != null && e != null && (a.StartsWith(e)));
        }
Ejemplo n.º 17
0
        public static IEnumerable <IElementNavigator> Descendants(this IElementNavigator navigator)
        {
            //TODO: Don't think this is performant with these nested yields
            foreach (var child in navigator.Children())
            {
                yield return(child);

                foreach (var grandchild in child.Descendants())
                {
                    yield return(grandchild);
                }
            }
        }
Ejemplo n.º 18
0
        public static Model.Quantity ParseQuantity(this IElementNavigator instance)
        {
            var newQuantity = new Quantity();

            newQuantity.Value = instance.Children("value").SingleOrDefault()?.Value as decimal?;

            var comp = instance.Children("comparator").GetString();

            if (comp != null)
            {
                newQuantity.ComparatorElement = new Code <Quantity.QuantityComparator> {
                    ObjectValue = comp
                }
            }
            ;

            newQuantity.Unit   = instance.Children("unit").GetString();
            newQuantity.System = instance.Children("system").GetString();
            newQuantity.Code   = instance.Children("code").GetString();

            return(newQuantity);
        }
Ejemplo n.º 19
0
#pragma warning disable 612, 618
        public IEnumerable <Tuple <string, IFhirReader> > GetMembers()
        {
            if (Value != null)
            {
                yield return(Tuple.Create("value", (IFhirReader) new ElementNavFhirReader(_current)));
            }

            foreach (var child in _current.Children())
            {
                bool mustSkip = verifyXmlSpecificDetails(child);

                if (!mustSkip)
                {
                    yield return(Tuple.Create(child.Name, (IFhirReader) new ElementNavFhirReader(child)));
                }
            }
        }
Ejemplo n.º 20
0
        public static MatchResult Match(ElementDefinitionNavigator definitionParent, IElementNavigator instanceParent)
        {
            List <ElementDefinitionNavigator> definitionElements = harvestDefinitionNames(definitionParent);
            List <IElementNavigator>          elementsToMatch    = instanceParent.Children().ToList();

            List <Match> matches = new List <Match>();

            foreach (var definitionElement in definitionElements)
            {
                var match = new Match()
                {
                    Definition = definitionElement, InstanceElements = new List <IElementNavigator>()
                };

                // Special case is the .value of a primitive fhir type, this is represented
                // as the "Value" of the IValueProvider interface, not as a real child
                if (definitionElement.Current.IsPrimitiveValueConstraint())
                {
                    if (instanceParent.Value != null)
                    {
                        match.InstanceElements.Add(instanceParent);
                    }
                }
                else
                {
                    var definitionPath = ProfileNavigationExtensions.GetNameFromPath(definitionElement.Current?.Base?.Path ?? definitionElement.Path);
                    var found          = elementsToMatch.Where(ie => NameMatches(definitionPath, ie)).ToList();

                    match.InstanceElements.AddRange(found);
                    elementsToMatch.RemoveAll(e => found.Contains(e));
                }

                matches.Add(match);
            }

            MatchResult result = new MatchResult();

            result.Matches = matches;
            result.UnmatchedInstanceElements = elementsToMatch;

            return(result);
        }
        public static bool Matches(this IElementNavigator value, IElementNavigator pattern)
        {
            if (value == null && pattern == null)
            {
                return(true);
            }
            if (value == null || pattern == null)
            {
                return(false);
            }

            if (!ValueEquality(value.Value, pattern.Value))
            {
                return(false);
            }

            // Compare the children.
            var valueChildren   = value.Children();
            var patternChildren = pattern.Children();

            return(patternChildren.All(patternChild => valueChildren.Any(valueChild =>
                                                                         patternChild.Name == valueChild.Name && valueChild.Matches(patternChild))));
        }
Ejemplo n.º 22
0
        public static string AsJson(this IElementNavigator navigator, int indent = 0)
        {
            var builder = new StringBuilder();
            var pad     = new string(' ', indent * 2);

            if (navigator.HasChildren())
            {
                builder.Append($"{pad}{navigator.Name}: ");
                builder.Append("{\n");

                foreach (var child in navigator.Children())
                {
                    builder.Append(AsJson(child, indent + 1));
                }
                builder.Append(pad + "},\n");
            }
            else
            {
                string content = $"{pad}{navigator.Name}: \"{navigator.Value}\",\n";
                builder.Append(content);
            }
            return(builder.ToString());
        }
        internal static OperationOutcome ValidateResourceReference(this Validator validator, IElementNavigator instance, ElementDefinition.TypeRefComponent typeRef)
        {
            var outcome = new OperationOutcome();

            var references = instance.Children("reference");
            var reference  = references.FirstOrDefault()?.Value as string;

            if (reference == null)       // No reference found -> this is always valid
            {
                return(outcome);
            }

            if (references.Count() > 1)
            {
                validator.Trace(outcome, $"Encountered multiple references, just using first ({reference})", Issue.CONTENT_REFERENCE_HAS_MULTIPLE_REFERENCES, instance);
            }

            // Try to resolve the reference *within* the current instance (Bundle, resource with contained resources) first
            ElementDefinition.AggregationMode?encounteredKind;
            var referencedResource = validator.ResolveReference(instance, reference, out encounteredKind, outcome);

            // Validate the kind of aggregation.
            // If no aggregation is given, all kinds of aggregation are allowed, otherwise only allow
            // those aggregation types that are given in the Aggregation element
            bool hasAggregation = typeRef.Aggregation != null && typeRef.Aggregation.Count() != 0;

            if (hasAggregation && !typeRef.Aggregation.Any(a => a == encounteredKind))
            {
                validator.Trace(outcome, $"Encountered a reference ({reference}) of kind '{encounteredKind}' which is not allowed", Issue.CONTENT_REFERENCE_OF_INVALID_KIND, instance);
            }

            // If we failed to find a referenced resource within the current instance, try to resolve it using an external method
            if (referencedResource == null && encounteredKind == ElementDefinition.AggregationMode.Referenced)
            {
                try
                {
                    referencedResource = validator.ExternalReferenceResolutionNeeded(reference, outcome, instance);
                }
                catch (Exception e)
                {
                    validator.Trace(outcome, $"Resolution of external reference {reference} failed. Message: {e.Message}",
                                    Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance);
                }
            }

            // If the reference was resolved (either internally or externally, validate it
            if (referencedResource != null)
            {
                validator.Trace(outcome, $"Starting validation of referenced resource {reference} ({encounteredKind})", Issue.PROCESSING_START_NESTED_VALIDATION, instance);

                // References within the instance are dealt with within the same validator,
                // references to external entities will operate within a new instance of a validator (and hence a new tracking context).
                // In both cases, the outcome is included in the result.
                if (encounteredKind != ElementDefinition.AggregationMode.Referenced)
                {
                    outcome.Include(validator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null));
                }
                else
                {
                    var newValidator = validator.NewInstance();
                    outcome.Include(newValidator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null));
                }
            }
            else
            {
                validator.Trace(outcome, $"Cannot resolve reference {reference}", Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance);
            }

            return(outcome);
        }
        /// <summary>
        /// Parses a bindeable type (code, Coding, CodeableConcept, Quantity, string, uri) into a FHIR coded datatype.
        /// Extensions will be parsed from the 'value' of the (simple) extension.
        /// </summary>
        /// <param name="instance"></param>
        /// <returns>An Element of a coded type (code, Coding or CodeableConcept) dependin on the instance type,
        /// or null if no bindable instance data was found</returns>
        /// <remarks>The instance type is mapped to a codable type as follows:
        ///   'code' => code
        ///   'Coding' => Coding
        ///   'CodeableConcept' => CodeableConcept
        ///   'Quantity' => Coding
        ///   'Extension' => depends on value[x]
        ///   'string' => code
        ///   'uri' => code
        /// </remarks>
        public static Element ParseBindable(this IElementNavigator instance)
        {
            var instanceType = ModelInfo.FhirTypeNameToFhirType(instance.Type);

            switch (instanceType)
            {
            case FHIRDefinedType.Code:
                return(instance.ParsePrimitive <Code>());

            case FHIRDefinedType.Coding:
                return(instance.ParseCoding());

            case FHIRDefinedType.CodeableConcept:
                return(instance.ParseCodeableConcept());

            case FHIRDefinedType.Quantity:
                return(parseQuantity(instance));

            case FHIRDefinedType.String:
                return(new Code(instance.ParsePrimitive <FhirString>()?.Value));

            case FHIRDefinedType.Uri:
                return(new Code(instance.ParsePrimitive <FhirUri>()?.Value));

            case FHIRDefinedType.Extension:
                return(parseExtension(instance));

            case null:
            //HACK: fall through - IElementNav did not provide a type
            //should not happen, and I have no intention to handle it.
            default:
                // Not bindable
                return(null);
            }

            Coding parseQuantity(IElementNavigator nav)
            {
                var newCoding = new Coding();
                var q         = instance.ParseQuantity();

                newCoding.Code   = q.Unit;
                newCoding.System = q.System ?? "http://unitsofmeasure.org";
                return(newCoding);
            }

            Element parseExtension(IElementNavigator nav)
            {
                // HACK: For now, assume this is a typed navigator, so we have "value",
                // not the unparsed "valueCode" etc AND we have Type (in ParseBindable())
                var valueChild = instance.Children("value").FirstOrDefault();

                if (valueChild != null)
                {
                    return(valueChild.ParseBindable());
                }
                else
                {
                    return(null);
                }
            }
        }
 public IEnumerable <ISourceNode> Children(string name = null) =>
 Current.Children()
 .Select(c => new ElementNavToSourceNodeAdapter(this, c))
 .Where(c => c.Name.MatchesPrefix(name));
 public IEnumerable <ITypedElement> Children(string name = null) =>
 Current.Children(name).Select(c => new ElementNavToTypedElementAdapter(this, c));
 public static bool HasChildren(this IElementNavigator navigator, string name = null)
 {
     return(navigator.Children(name).Any());
 }
Ejemplo n.º 28
0
        public static bool IsEqualTo(this IElementNavigator left, IElementNavigator right, bool compareNames = false)
        {
            if (compareNames && (left.Name != right.Name))
            {
                return(false);
            }

            var l = left.Value;
            var r = right.Value;

            // Compare primitives (or extended primitives)
            if (l != null && r != null)
            {
                if (l.GetType() == typeof(string) && r.GetType() == typeof(string))
                {
                    return((string)l == (string)r);
                }
                else if (l.GetType() == typeof(bool) && r.GetType() == typeof(bool))
                {
                    return((bool)l == (bool)r);
                }
                else if (l.GetType() == typeof(long) && r.GetType() == typeof(long))
                {
                    return((long)l == (long)r);
                }
                else if (l.GetType() == typeof(decimal) && r.GetType() == typeof(decimal))
                {
                    return((decimal)l == (decimal)r);
                }
                else if (l.GetType() == typeof(long) && r.GetType() == typeof(decimal))
                {
                    return((decimal)(long)l == (decimal)r);
                }
                else if (l.GetType() == typeof(decimal) && r.GetType() == typeof(long))
                {
                    return((decimal)l == (decimal)(long)r);
                }
                else if (l.GetType() == typeof(PartialTime) && r.GetType() == typeof(PartialTime))
                {
                    return((PartialTime)l == (PartialTime)r);
                }
                else if (l.GetType() == typeof(PartialDateTime) && r.GetType() == typeof(PartialDateTime))
                {
                    return((PartialDateTime)l == (PartialDateTime)r);
                }
                else
                {
                    return(false);
                }
            }
            else if (l == null && r == null)
            {
                // Compare complex types (extensions on primitives are not compared, but handled (=ignored) above
                var childrenL = left.Children();
                var childrenR = right.Children();

                return(childrenL.IsEqualTo(childrenR, compareNames: true));    // NOTE: Assumes null will never be returned when any() children exist
            }
            else
            {
                // Else, we're comparing a complex (without a value) to a primitive which (probably) should return false
                return(false);
            }
        }
Ejemplo n.º 29
0
 public static IEnumerable <string> GetChildNames(this IElementNavigator navigator)
 {
     return(navigator.Children().Select(c => c.Name).Distinct());
 }
Ejemplo n.º 30
0
 public static IEnumerable <IElementNavigator> GetChildrenByName(this IElementNavigator navigator, string name)
 {
     return(navigator.Children().Where(c => c.Name == name));
 }