/// <summary>Harvest specific summary information from a <see cref="StructureDefinition"/> resource.</summary>
        /// <returns><c>true</c> if the current target represents a <see cref="StructureDefinition"/> resource, or <c>false</c> otherwise.</returns>
        /// <remarks>The <see cref="ArtifactSummaryGenerator"/> calls this method from a <see cref="ArtifactSummaryHarvester"/> delegate.</remarks>
        public static bool Harvest(ISourceNode nav, ArtifactSummaryPropertyBag properties)
        {
            if (IsStructureDefinitionSummary(properties))
            {
                // [WMR 20171218] Harvest global core extensions, e.g. MaturityLevel
                nav.HarvestExtensions(properties, harvestExtension);

                // Explicit extractor chaining
                if (ConformanceSummaryProperties.Harvest(nav, properties))
                {
                    nav.HarvestValue(properties, FhirVersionKey, "fhirVersion");
                    nav.HarvestValue(properties, KindKey, "kind");
                    nav.HarvestValue(properties, ConstrainedTypeKey, "constrainedType");
                    nav.HarvestValue(properties, ContextTypeKey, "contextType");
                    // [WMR 20180919] NEW: Extension Context
                    nav.HarvestValues(properties, ContextKey, "context");
                    nav.HarvestValue(properties, BaseKey, "base");

                    // [WMR 20180725] Also harvest definition property from (first) root element in snapshot/differential
                    // HL7 FHIR website displays this text as introduction on top of each resource/datatype page
                    var elementNode = nav.Children("snapshot").FirstOrDefault() ?? nav.Children("differential").FirstOrDefault();
                    if (elementNode != null)
                    {
                        var childNode = elementNode.Children("element").FirstOrDefault();
                        if (childNode != null && Navigation.ElementDefinitionNavigator.IsRootPath(childNode.Name))
                        {
                            childNode.HarvestValue(properties, RootDefinitionKey, "definition");
                        }
                    }
                }
                return(true);
            }
            return(false);
        }
Ejemplo n.º 2
0
        public static void ElementNavPerformance(ISourceNode nav)
        {
            // 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().Text;

                Assert.IsNotNull(usual);
                var phone = nav.Children("telecom").First().Children("system").First().Text;

                Assert.IsNotNull(usual);
                var prefs = nav.Children("communication").Where(c => c.Children("preferred").Any(pr => pr.Text == "true")).Count();

                Assert.AreNotEqual(0, prefs);
                var link = nav.Children("link").Children("other").Children("reference");

                Assert.IsNotNull(link);
            }
        }
Ejemplo n.º 3
0
        internal Base Deserialize(ClassMapping mapping, Base existing = null)
        {
            if (mapping == null)
            {
                throw Error.ArgumentNull(nameof(mapping));
            }

            if (existing == null)
            {
                var fac = new DefaultModelFactory();
                existing = (Base)fac.Create(mapping.NativeType);
            }
            else
            {
                if (mapping.NativeType != existing.GetType())
                {
                    throw Error.Argument(nameof(existing), "Existing instance is of type {0}, but data indicates resource is a {1}".FormatWith(existing.GetType().Name, mapping.NativeType.Name));
                }
            }

            var members = _current.Text != null ?
                          new[] { SourceNode.Valued("value", _current.Text) }.Union(_current.Children()) :
            _current.Children();

            read(mapping, members, existing);

            return(existing);
        }
Ejemplo n.º 4
0
        private IEnumerable <TypedElementNode> enumerateElements(ElementDefinitionSummaryCache dis, ISourceNode parent, string name)
        {
            IEnumerable <ISourceNode> childSet = null;

            // no name filter: work on all the parent's children
            if (name == null)
            {
                childSet = parent.Children();
            }
            else
            {
                var hit = dis.TryGetBySuffixedName(name, out var info);
                childSet = hit && info.IsChoiceElement ?
                           parent.Children(name + "*") :
                           parent.Children(name);
            }

            string lastName   = null;
            int    _nameIndex = 0;

            foreach (var scan in childSet)
            {
                var hit = dis.TryGetBySuffixedName(scan.Name, out var info);
                NavigatorPosition match = info == null ?
                                          new NavigatorPosition(scan, null, scan.Name, null) :
                                          deriveInstanceType(scan, info);

                // If we found a type, but we don't know about the specific child, complain
                if (dis != ElementDefinitionSummaryCache.Empty && !match.IsTracking)
                {
                    raiseTypeError($"Encountered unknown element '{scan.Name}' while parsing", this,
                                   warning: _settings.ErrorMode != TypedElementSettings.TypeErrorMode.Report);

                    // don't include member, unless we are explicitly told to let it pass
                    if (_settings.ErrorMode != TypedElementSettings.TypeErrorMode.Passthrough)
                    {
                        continue;
                    }
                }

                if (lastName == scan.Name)
                {
                    _nameIndex += 1;
                }
                else
                {
                    _nameIndex = 0;
                    lastName   = scan.Name;
                }

                var prettyPath =
                    hit && !info.IsCollection ? $"{ShortPath}.{match.Name}" : $"{ShortPath}.{match.Name}[{_nameIndex}]";

                yield return(new TypedElementNode(this, match, prettyPath));
            }
        }
        private IEnumerable <TypedElementOnSourceNode> enumerateElements(Dictionary <string, IElementDefinitionSummary> dis, ISourceNode parent, string name)
        {
            IEnumerable <ISourceNode> childSet;

            // no name filter: work on all the parent's children
            if (name == null)
            {
                childSet = parent.Children();
            }
            else
            {
                var hit = tryGetBySuffixedName(dis, name, out var info);
                childSet = hit && info.IsChoiceElement ?
                           parent.Children(name + "*") :
                           parent.Children(name);
            }

            string lastName   = null;
            int    _nameIndex = 0;

            foreach (var scan in childSet)
            {
                var    hit          = tryGetBySuffixedName(dis, scan.Name, out var info);
                string instanceType = info == null ? null :
                                      deriveInstanceType(scan, info);

                // If we have definitions for the children, but we didn't find definitions for this
                // child in the instance, complain
                if (dis.Any() && info == null)
                {
                    raiseTypeError($"Encountered unknown element '{scan.Name}' at location '{scan.Location}' while parsing", this,
                                   warning: _settings.ErrorMode != TypedElementSettings.TypeErrorMode.Report);

                    // don't include member, unless we are explicitly told to let it pass
                    if (_settings.ErrorMode != TypedElementSettings.TypeErrorMode.Passthrough)
                    {
                        continue;
                    }
                }

                if (lastName == scan.Name)
                {
                    _nameIndex += 1;
                }
                else
                {
                    _nameIndex = 0;
                    lastName   = scan.Name;
                }

                var prettyPath =
                    hit && !info.IsCollection ? $"{ShortPath}.{info.ElementName}" : $"{ShortPath}.{scan.Name}[{_nameIndex}]";

                yield return(new TypedElementOnSourceNode(this, scan, info, instanceType, prettyPath));
            }
        }
Ejemplo n.º 6
0
        public static void ProducesCorrectUntypedLocations(ISourceNode patient)
        {
            Assert.AreEqual("Patient", patient.Location);

            Assert.AreEqual("Patient.id[0]", patient.Children().First().Location);
            var identifiers = patient.Children("identifier").ToList();

            Assert.AreEqual("Patient.identifier[0]", identifiers[0].Location);
            Assert.AreEqual("Patient.identifier[0].use[0]", identifiers[0].Children().First().Location);
            Assert.AreEqual("Patient.identifier[1]", identifiers[1].Location);
            Assert.AreEqual("Patient.identifier[1].use[0]", identifiers[1].Children().First().Location);
            Assert.AreEqual("Patient.deceasedBoolean[0]", patient.Children("deceasedBoolean").Single().Location);
            Assert.AreEqual("Patient.contained[0].name[1].use[0]",
                            patient.Children("contained").First().Children("name").Skip(1).First().Children("use").Single().Location);
        }
Ejemplo n.º 7
0
        /// <summary>Harvest the value of a child element into a property bag.</summary>
        /// <param name="nav">An <see cref="ISourceNode"/> instance.</param>
        /// <param name="properties">A property bag to store harvested summary information.</param>
        /// <param name="key">A property key.</param>
        /// <param name="element">An element name.</param>
        /// <param name="childElement">A child element name.</param>
        public static bool HarvestValue(this ISourceNode nav, IDictionary <string, object> properties, string key, string element, string childElement)
        {
            var elementNode = nav.Children(element).FirstOrDefault();
            var childNode   = elementNode?.Children(childElement).FirstOrDefault();

            return(childNode != null && HarvestValue(childNode, properties, key));
        }
Ejemplo n.º 8
0
        private static SourceNode buildNode(ISourceNode node, bool recursive, IEnumerable <Type> annotationsToCopy)
        {
            var me = new SourceNode(node.Name, node.Text);

            var rts = node.Annotation <IResourceTypeSupplier>();

            if (rts != null)
            {
                me.ResourceType = rts.ResourceType;
            }

            foreach (var t in annotationsToCopy ?? Enumerable.Empty <Type>())
            {
                foreach (var ann in node.Annotations(t))
                {
                    me.AddAnnotation(ann);
                }
            }

            if (recursive)
            {
                me.AddRange(node.Children().Select(c => buildNode(c, recursive: true, annotationsToCopy: annotationsToCopy)));
            }

            return(me);
        }
Ejemplo n.º 9
0
        private void WriteNode(ISourceNode node, TextWriter writer)
        {
            bool isFlat = node.GetType().GetCustomAttribute <FlatAttribute>() != null;

            foreach (var line in node.Prefix())
            {
                writer.Write(styleStack.Peek());
                writer.WriteLine(line);
            }

            if (!isFlat)
            {
                styleStack.Push(styleStack.Peek() + indent);
            }

            foreach (var child in node.Children())
            {
                WriteNode(child, writer);
            }

            if (!isFlat)
            {
                styleStack.Pop();
            }

            foreach (var line in node.Suffix())
            {
                writer.Write(styleStack.Peek());
                writer.WriteLine(line);
            }
        }
Ejemplo n.º 10
0
        private static SourceNode buildNode(ISourceNode node)
        {
            var me = new SourceNode(node.Name, node.Text);

            me.AddRange(node.Children().Select(c => buildNode(c)));
            return(me);
        }
 private static void visit(this ISourceNode navigator, Action <int, ISourceNode> visitor, int depth = 0)
 {
     visitor(depth, navigator);
     foreach (var child in navigator.Children())
     {
         visit(child, visitor, depth + 1);
     }
 }
        private void _DumpNode(ISourceNode node)
        {
            Console.WriteLine($"{node.Location,70} {node.Name,20} {node.Text}");

            foreach (ISourceNode child in node.Children())
            {
                _DumpNode(child);
            }
        }
        // Generate summary for a single artifact
        static ArtifactSummary generate(
            ArtifactSummaryPropertyBag props,
            ISourceNode nav,
            ArtifactSummaryHarvester[] harvesters)
        {
            Exception error = null;

            // [WMR 20180419] Support empty harvester list (harvest only default props, no custom props)
            if (harvesters != null && harvesters.Length > 0)
            {
                try
                {
                    // Harvest summary information via specified harvesters
                    // Top-level harvesters receive navigator positioned on the first child element level

                    // Catch individual exceptions inside loop, return as AggregateException
                    var errors = new List <Exception>();
                    if (nav.Children().Any())
                    {
                        foreach (var harvester in harvesters)
                        {
                            try
                            {
                                if (harvester != null && harvester.Invoke(nav, props))
                                {
                                    break;
                                }
                            }
                            // TODO Catch specific exceptions
                            // catch (FormatException)
                            catch (Exception ex)
                            {
                                errors.Add(ex);
                            }
                        }
                    }

                    // Combine all errors into single AggregateException
                    error = errors.Count > 0 ? new AggregateException(errors) : null;
                }
                // TODO Catch specific exceptions
                // catch (FormatException)
                // catch (NotSupportedException)
                catch (Exception ex)
                {
                    // Error in summary factory?
                    // Make sure we always return a valid summary
                    error = ex;
                }
            }

            // Create final summary from harvested properties and optional error
            return(new ArtifactSummary(props, error));
        }
 // Callback for HarvestExtensions, called for each individual extension entry
 static void harvestExtension(ISourceNode nav, IDictionary <string, object> properties, string url)
 {
     if (StringComparer.Ordinal.Equals(FmmExtensionUrl, url))
     {
         var child = nav.Children("valueInteger").FirstOrDefault();
         if (child != null)
         {
             properties[MaturityLevelKey] = child.Text;
         }
     }
 }
Ejemplo n.º 15
0
        public static void HasLineNumbers <T>(ISourceNode nav) where T : class, IPositionInfo
        {
            nav = nav.Children().FirstOrDefault();
            Assert.IsNotNull(nav);

            var posInfo = (nav as IAnnotated)?.Annotation <T>();

            Assert.IsNotNull(posInfo);
            Assert.AreNotEqual(-1, posInfo.LineNumber);
            Assert.AreNotEqual(-1, posInfo.LinePosition);
            Assert.AreNotEqual(0, posInfo.LineNumber);
            Assert.AreNotEqual(0, posInfo.LinePosition);
        }
Ejemplo n.º 16
0
        /// <summary>Harvest extension values into a property bag.</summary>
        /// <param name="nav">An <see cref="ISourceNode"/> instance.</param>
        /// <param name="properties">A property bag to store harvested summary information.</param>
        /// <param name="extensionValueHarvester">Callback function called for each individual extension entry.</param>
        public static void HarvestExtensions(this ISourceNode nav, IDictionary <string, object> properties, Action <ISourceNode, IDictionary <string, object>, string> extensionValueHarvester)
        {
            const string extension = "extension";

            foreach (var child in nav.Children(extension))
            {
                var url = child.Children("url").FirstOrDefault();
                if (url != null)
                {
                    extensionValueHarvester(child, properties, url.Text);
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>Harvest an array of element values into a property bag.</summary>
        /// <param name="nav">An <see cref="ISourceNode"/> instance.</param>
        /// <param name="properties">A property bag to store harvested summary information.</param>
        /// <param name="key">A property key.</param>
        /// <param name="element">An element name.</param>
        public static bool HarvestValues(this ISourceNode nav, IDictionary <string, object> properties, string key, string element)
        {
            var values = new List <string>();

            foreach (var elementNode in nav.Children(element))
            {
                HarvestValue(elementNode, values);
            }
            if (values.Count > 0)
            {
                properties[key] = values.ToArray();
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// Returns all descendants of a node.
        /// </summary>
        /// <param name="node">A node.</param>
        /// <returns>The descendants (children and by recursion all children of the children) of the node passed into
        /// <paramref name="node"/></returns>
        public static IEnumerable <ISourceNode> Descendants(this ISourceNode node)
        {
            if (node == null)
            {
                throw Error.ArgumentNull(nameof(node));
            }

            foreach (var child in node.Children())
            {
                yield return(child);

                foreach (var grandchild in child.Descendants())
                {
                    yield return(grandchild);
                }
            }
        }
Ejemplo n.º 19
0
        private void AddLocations(ISourceNode node, ref IPositionInfo lastNode, ref int lastCharPos, char[] chars)
        {
            int           location = 0;
            IPositionInfo posInfo  = (node as IAnnotated)?.Annotation <Hl7.Fhir.Serialization.XmlSerializationDetails>();

            if (posInfo == null)
            {
                posInfo = (node as IAnnotated)?.Annotation <Hl7.Fhir.Serialization.JsonSerializationDetails>();
            }
            if (posInfo != null)
            {
                if (lastNode == null)
                {
                    location = 0;
                }
                else
                {
                    var linesToSkip = posInfo.LineNumber - lastNode.LineNumber;
                    var colsToSkip  = posInfo.LinePosition;
                    if (linesToSkip == 0)
                    {
                        colsToSkip -= lastNode.LinePosition;
                    }
                    while (linesToSkip > 0 && lastCharPos < chars.Length)
                    {
                        lastCharPos++;
                        if (chars[lastCharPos] == '\r')
                        {
                            linesToSkip--;
                        }
                    }
                    lastCharPos += colsToSkip;
                    location     = lastCharPos; // need to patch this
                }
                lastNode = posInfo;
                _locations.Add(location, node.Location);
                // System.Diagnostics.Trace.WriteLine($"{location}: {node.Location}");
            }
            lastCharPos = location;
            foreach (var child in node.Children())
            {
                AddLocations(child, ref lastNode, ref lastCharPos, chars);
            }
        }
        public static TreeComparisonResult IsEqualTo(this ISourceNode expected, ISourceNode actual)
        {
            if (expected.Name != actual.Name)
            {
                return(TreeComparisonResult.Fail(actual.Location, $"name: was '{actual.Name}', expected '{expected.Name}'"));
            }
            if (expected.Text != actual.Text)
            {
                return(TreeComparisonResult.Fail(actual.Location, $"value: was '{actual.Text}', expected '{expected.Text}'"));
            }
            if (expected.Location != actual.Location)
            {
                TreeComparisonResult.Fail(actual.Location, $"Path: 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())
                {
                    TreeComparisonResult.Fail(actual.Location, $"number of children was different");
                }

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

            return(TreeComparisonResult.OK);
        }
        private string deriveInstanceType(ISourceNode current, IElementDefinitionSummary info)
        {
            var resourceTypeIndicator = current.GetResourceTypeIndicator();

            // First, handle the case where this (appears to be) a resource.
            if (info.IsResource)
            {
                if (resourceTypeIndicator == null)
                {
                    raiseTypeError($"Element '{current.Name}' should contain a resource, but does not actually contain one", current, location: current.Location);
                }
                return(resourceTypeIndicator);
            }
            else if (resourceTypeIndicator != null)
            {
                raiseTypeError($"Element '{current.Name}' is not a contained resource, but seems to contain a resource of type '{resourceTypeIndicator}'.", current, location: current.Location);
                return(resourceTypeIndicator);
            }

            // Now, it's a data element. But is a choice, so we need to take
            // a look at the suffix on the element's name to figure out what we
            // are dealing with.
            if (info.IsChoiceElement)
            {
                var suffix = current.Name.Substring(info.ElementName.Length);

                if (string.IsNullOrEmpty(suffix))
                {
                    raiseTypeError($"Choice element '{current.Name}' is not suffixed with a type.", current, location: current.Location);
                    return(null);
                }

                suffix = normalizeSuffix(suffix);

                // If any of the types is the abstract 'DataType' type, we'll just
                // accept whatever type is mentioned, we have no real list to go on =>
                // An example of where this happens is Extension.value[x], which is
                // a POCO that is common to all (FHIR) datamodels, and since value[x] is an
                // "open" types, we have no idea which types are allowed.
                if (info.Type.Any(t => t.GetTypeName() == "DataType"))
                {
                    return(suffix);
                }
                else
                {
                    var isListed = info.Type
                                   .OfType <IStructureDefinitionReference>()
                                   .Select(t => t.ReferredType)
                                   .Any(t => t == suffix);

                    if (!isListed)
                    {
                        raiseTypeError($"Choice element '{current.Name}' is suffixed with unexpected type '{suffix}'", current, location: current.Location);
                    }

                    return(suffix);
                }

                string normalizeSuffix(string s)
                {
                    // Unfortunately, we decided to nicely capitalize the suffix, even for
                    // primitives - luckily then, there's just a single list of primitives,
                    // so we can "correct" them
                    return(_suffixMap.TryGetValue(s, out var corrected) ? corrected : s);
                };
            }
            else if (info.Representation == XmlRepresentation.TypeAttr) // May be used by models other then FHIR, e.g. CCDA represented by a StructureDefinition
            {
                if (info.Type.Count() == 1)
                {
                    return(info.Type.Single().GetTypeName());
                }
                else
                {
                    var typeName = current.Children("type").FirstOrDefault()?.Text;
                    return(typeName != null
                        ? info.Type.Where(type => typeFromLogicalModelCanonical(type).Equals(typeName)).FirstOrDefault()?.GetTypeName()
                        : info.DefaultTypeName);
                }
            }

            var tp = info.Type.Single();

            return(tp.GetTypeName());
        }
        private string deriveInstanceType(ISourceNode current, IElementDefinitionSummary info)
        {
            string instanceType          = null;
            var    resourceTypeIndicator = current.GetResourceTypeIndicator();

            if (info.IsResource)
            {
                instanceType = resourceTypeIndicator;
                if (instanceType == null)
                {
                    raiseTypeError($"Element '{current.Name}' should contain a resource, but does not actually contain one", current, location: current.Location);
                }
            }
            else if (!info.IsResource && resourceTypeIndicator != null)
            {
                raiseTypeError($"Element '{current.Name}' is not a contained resource, but seems to contain a resource of type '{resourceTypeIndicator}'.", current, location: current.Location);
                instanceType = resourceTypeIndicator;
            }
            else if (info.IsChoiceElement)
            {
                var suffix = current.Name.Substring(info.ElementName.Length);

                if (string.IsNullOrEmpty(suffix))
                {
                    raiseTypeError($"Choice element '{current.Name}' is not suffixed with a type.", current, location: current.Location);
                    instanceType = null;
                }
                else
                {
                    instanceType = info.Type
                                   .OfType <IStructureDefinitionReference>()
                                   .Select(t => t.ReferredType)
                                   .FirstOrDefault(t => string.Compare(t, suffix, System.StringComparison.OrdinalIgnoreCase) == 0);

                    if (string.IsNullOrEmpty(instanceType))
                    {
                        raiseTypeError($"Choice element '{current.Name}' is suffixed with unexpected type '{suffix}'", current, location: current.Location);
                    }
                }
            }
            else if (info.Representation == XmlRepresentation.TypeAttr) // May be used by models other then FHIR, e.g. CCDA represented by a StructureDefinition
            {
                if (info.Type.Count() == 1)
                {
                    instanceType = info.Type.Single().GetTypeName();
                }
                else
                {
                    var typeName = current.Children("type").FirstOrDefault()?.Text;
                    if (typeName != null)
                    {
                        instanceType = info.Type.Where(type => typeFromLogicalModelCanonical(type).Equals(typeName)).FirstOrDefault()?.GetTypeName();
                    }
                    else
                    {
                        instanceType = info.DefaultTypeName;
                    }
                }
            }
            else
            {
                var tp = info.Type.Single();
                instanceType = tp.GetTypeName();
            }

            return(instanceType);
        }
        private IEnumerable <TypedElementOnSourceNode> enumerateElements(Dictionary <string, IElementDefinitionSummary> dis, ISourceNode parent, string name)
        {
            IEnumerable <ISourceNode> childSet;

            // no name filter: work on all the parent's children
            if (name == null)
            {
                childSet = parent.Children();
            }
            else
            {
                var hit = tryGetBySuffixedName(dis, name, out var info);
                childSet = hit && info.IsChoiceElement ?
                           parent.Children(name + "*") :
                           parent.Children(name);
            }

            string lastName   = null;
            int    _nameIndex = 0;

            foreach (var scan in childSet)
            {
                var    hit          = tryGetBySuffixedName(dis, scan.Name, out var info);
                string instanceType = info == null ? null :
                                      deriveInstanceType(scan, info);

                // If we have definitions for the children, but we didn't find definitions for this
                // child in the instance, complain
                if (dis.Any() && info == null)
                {
                    raiseTypeError($"Encountered unknown element '{scan.Name}' at location '{scan.Location}' while parsing", this,
                                   warning: _settings.ErrorMode != TypedElementSettings.TypeErrorMode.Report);

                    // don't include member, unless we are explicitly told to let it pass
                    if (_settings.ErrorMode != TypedElementSettings.TypeErrorMode.Passthrough)
                    {
                        continue;
                    }
                }

                if (lastName == scan.Name)
                {
                    _nameIndex += 1;
                }
                else
                {
                    _nameIndex = 0;
                    lastName   = scan.Name;
                }

                var prettyPath =
                    hit && !info.IsCollection ? $"{ShortPath}.{info.ElementName}" : $"{ShortPath}.{scan.Name}[{_nameIndex}]";

                // Special condition for ccda.
                // If we encounter a xhtml node in a ccda document we will flatten all childnodes
                // and use their content to build up the xml.
                // The xml will be put in this node and children will be ignored.
                if (instanceType == XHTML_INSTANCETYPE && info.Representation == XmlRepresentation.CdaText)
                {
#pragma warning disable CS0618 // Type or member is obsolete
                    var xmls = scan.Children().Select(c => c.Annotation <ICdaInfoSupplier>()?.XHtmlText);
#pragma warning restore CS0618 // Type or member is obsolete

                    var source = SourceNode.Valued(scan.Name, string.Join(string.Empty, xmls));
                    yield return(new TypedElementOnSourceNode(this, source, info, instanceType, prettyPath));

                    continue;
                }

                yield return(new TypedElementOnSourceNode(this, scan, info, instanceType, prettyPath));
            }
        }
 public IEnumerable <ITypedElement> Children(string name) =>
 Current.Children(name).Select(c => new SourceNodeToTypedElementAdapter(this, c));