#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? }); }
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)); }
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)); } }
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); } }
public string Id() { if (_cache.Id == null) { _cache.Id = AtResource ? "#" + _wrapped.Children("id").FirstOrDefault()?.Value as string : null; } return(_cache.Id); }
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()))))); }
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))); }
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); } } }
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); }
#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))); } } }
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)))); }
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()); }
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); } }
public static IEnumerable <string> GetChildNames(this IElementNavigator navigator) { return(navigator.Children().Select(c => c.Name).Distinct()); }
public static IEnumerable <IElementNavigator> GetChildrenByName(this IElementNavigator navigator, string name) { return(navigator.Children().Where(c => c.Name == name)); }