/// <summary>
        /// Advance the navigator to the first reslice of the current named slice.
        /// Skip any existing child elements and/or child reslicing constraints.
        /// Otherwise remain positioned at the current element.
        /// </summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool MoveToFirstReslice(this ElementDefinitionNavigator nav)
        {
            if (nav == null)
            {
                throw Error.ArgumentNull(nameof(nav));
            }
            if (nav.Current == null)
            {
                throw Error.Argument(nameof(nav), "Cannot move navigator to previous slice. Current node is not set.");
            }

            var sliceName = nav.Current.Name;

            if (string.IsNullOrEmpty(sliceName))
            {
                throw Error.Argument(nameof(nav), "The current element is not a named slice.");
            }

            var bm = nav.Bookmark();

            if (nav.MoveToNextSliceAtAnyLevel())
            {
                if (ElementDefinitionNavigator.IsResliceOf(nav.Current.Name, sliceName))
                {
                    return(true);
                }
            }

            // No match, restore original position
            nav.ReturnToBookmark(bm);
            return(false);
        }
 /// <summary>Determines if the element with the specified name represents a type slice for the current (choice) element.</summary>
 /// <returns><c>true</c> if the element name represents a type slice of the current element, <c>false</c> otherwise.</returns>
 internal static bool IsRenamedChoiceTypeElement(this ElementDefinitionNavigator nav, string diffName)
 {
     if (nav == null)
     {
         throw Error.ArgumentNull(nameof(nav));
     }
     return(ElementDefinitionNavigator.IsRenamedChoiceTypeElement(nav.PathName, diffName));
 }
Пример #3
0
        public ElementDefinitionNavigator ShallowCopy()
        {
            var result = new ElementDefinitionNavigator();

            result.Elements            = this.Elements;
            result.OrdinalPosition     = this.OrdinalPosition;
            result.StructureDefinition = this.StructureDefinition;

            return(result);
        }
Пример #4
0
        public ElementDefinitionNavigator(ElementDefinitionNavigator other)
        {
            if (other == null)
            {
                throw Error.ArgumentNull(nameof(other));
            }

            Elements            = other.Elements.ToList();
            OrdinalPosition     = other.OrdinalPosition;
            StructureDefinition = other.StructureDefinition;
        }
        public static bool DeleteChildren(this ElementDefinitionNavigator nav)
        {
            var parent = nav.Bookmark();

            if (nav.MoveToFirstChild())
            {
                while (!nav.IsAtBookmark(parent))
                {
                    nav.DeleteTree();
                }
            }

            return(true);
        }
        /// <summary>
        /// Advance the navigator forward to the slicing constraint in the current slice group with the specified slice name.
        /// Otherwise remain positioned at the current element.
        /// </summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool MoveToNextSliceAtAnyLevel(this ElementDefinitionNavigator nav, string sliceName)
        {
            var bm = nav.Bookmark();

            while (nav.MoveToNextSliceAtAnyLevel())
            {
                if (StringComparer.Ordinal.Equals(nav.Current.Name, sliceName))
                {
                    return(true);
                }
            }
            nav.ReturnToBookmark(bm);
            return(false);
        }
        // [WMR 20160802] NEW - Move to the specified ElementDefinition

        /// <summary>Move the navigator to the specified element.</summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool MoveTo(this ElementDefinitionNavigator nav, ElementDefinition element)
        {
            if (nav == null)
            {
                throw Error.ArgumentNull(nameof(nav));
            }
            if (element == null)
            {
                throw Error.ArgumentNull(nameof(element));
            }

            var bm = new Bookmark(element);

            return(nav.ReturnToBookmark(bm));
        }
        /// <summary>Move the navigator to the first element with the specified path.</summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool JumpToFirst(this ElementDefinitionNavigator nav, string path)
        {
            // Find method performs parameter validation
            // if (nav == null) { throw Error.ArgumentNull(nameof(nav)); }
            // if (path == null) { throw Error.ArgumentNull(nameof(path)); }

            var matches = Find(nav, path);

            if (matches.Any())
            {
                nav.ReturnToBookmark(matches.First());
                return(true);
            }

            return(false);
        }
        /// <summary>Recursively clone the current element and all it's children and return a new navigator for the resulting subtree.</summary>
        /// <returns>A new <see cref="ElementDefinitionNavigator"/> instance that wraps the cloned element list.</returns>
        internal static ElementDefinitionNavigator CloneSubtree(this ElementDefinitionNavigator nav)
        {
            if (nav == null)
            {
                throw new ArgumentNullException(nameof(nav));
            }
            if (nav.Current == null)
            {
                throw new ArgumentException(nameof(nav));
            }

            var result = new ElementDefinitionNavigator(new ElementDefinition[] { (ElementDefinition)nav.Current.DeepCopy() });

            result.MoveToFirstChild();
            result.CopyChildren(nav);
            return(result);
        }
        private static IEnumerable <Bookmark> locateChildren(ElementDefinitionNavigator nav, IEnumerable <string> path, bool partial)
        {
            Debug.Assert(nav != null); // Caller should validate

            var child = path.First();
            var rest  = path.Skip(1);

            var bm = nav.Bookmark();

            if (nav.MoveToChild(child))
            {
                var result = new List <Bookmark>();

                do
                {
                    if (!rest.Any())
                    {
                        // Exact match!
                        result.Add(nav.Bookmark());
                    }
                    else if (!nav.HasChildren && partial)
                    {
                        // This is as far as we can get in this structure,
                        // so this is a hit too if partial hits are OK
                        result.Add(nav.Bookmark());
                    }
                    else
                    {
                        // So, no hit, but we have children that might fit the bill.
                        result.AddRange(locateChildren(nav, rest, partial));
                    }

                    // Try this for the other matching siblings too...
                }while (nav.MoveToNext(child));

                // We've scanned all my children and collected the results,
                // move the navigator back to where we were before
                nav.ReturnToBookmark(bm);
                return(result);
            }
            else
            {
                return(Enumerable.Empty <Bookmark>());
            }
        }
        // [WMR 20160802] NEW


        /// <summary>Move the navigator to the first preceding sibling element with the specified name, if it exists.</summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool MoveToPrevious(this ElementDefinitionNavigator nav, string name)
        {
            if (nav == null)
            {
                throw Error.ArgumentNull(nameof(nav));
            }
            var bm = nav.Bookmark();

            while (nav.MoveToPrevious())
            {
                if (nav.PathName == name)
                {
                    return(true);
                }
            }

            nav.ReturnToBookmark(bm);
            return(false);
        }
        /// <summary>
        /// Enumerate any succeeding direct child slices of the specified element.
        /// Skip any intermediate child elements and re-slice elements.
        /// When finished, return the navigator to the initial position.
        /// </summary>
        /// <param name="intro"></param>
        /// <param name="atRoot">Specify <c>true</c> for finding direct (simple) slices, or <c>false</c> for finding re-slices.</param>
        /// <returns>A sequence of <see cref="Bookmark"/> instances.</returns>
        internal static IEnumerable <Bookmark> FindMemberSlices(this ElementDefinitionNavigator intro, bool atRoot)
        {
            var bm = intro.Bookmark();

            var path     = intro.Current.Path;
            var pathName = intro.PathName;
            var name     = intro.Current.Name;

            while (intro.MoveToNext(pathName))
            {
                var curName = intro.Current.Name;
                if (atRoot)
                {
                    // Is this the slice-intro of the un-resliced original element? Then my name == null or
                    // (in DSTU2) my name has no slicing separator (since name is used both for slicing and
                    // re-use of constraints, e.g. Composition.section.name, just == null is not enough)
                    // I am the root slice, my slices would be the unnamed slices (though this is strictly seen not correct, every slice needs a name)
                    // and every slice with a non-resliced name
                    if (curName == null)
                    {
                        yield return(intro.Bookmark());
                    }
                    if (!ElementDefinitionNavigator.IsResliceName(curName))
                    {
                        yield return(intro.Bookmark());
                    }
                }
                else
                {
                    // Else, if I am a named slice, I am a slice myself, but also the intro to a nested re-sliced group,
                    // so include only my children in my group...
                    if (ElementDefinitionNavigator.IsResliceOf(curName, name))
                    {
                        yield return(intro.Bookmark());
                    }
                }

                // Else...there might be something wrong, I need to add logic here to find slices that are out of
                // order, of have a resliced name that does not start with the last slice intro we found.
            }

            intro.ReturnToBookmark(bm);
        }
        /// <summary>
        /// Insert the children of the source navigator under the node pointed to by this Navigator.
        /// </summary>
        /// <param name="dest"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool CopyChildren(this ElementDefinitionNavigator dest, ElementDefinitionNavigator source)
        {
            if (dest.HasChildren)
            {
                return(false);                    // Protect children from being overwritten
            }
            if (!source.MoveToFirstChild())
            {
                return(true);                               // Nothing to copy, but successful anyway
            }
            bool firstChild = true;

            do
            {
                var copiedChild = (ElementDefinition)source.Current.DeepCopy();

                if (firstChild)
                {
                    // The first time, create a new child in the destination
                    dest.InsertFirstChild(copiedChild);
                    firstChild = false;
                }
                else
                {
                    // Then insert other childs after that
                    dest.InsertAfter(copiedChild);
                }

                // If there are nested children in the source, insert them under
                // the newly inserted node in the destination
                if (source.HasChildren)
                {
                    dest.CopyChildren(source);
                }
            }while (source.MoveToNext());

            // Bring both source & destination back one step to the original parents
            source.MoveToParent();
            dest.MoveToParent();

            return(true);
        }
        /// <summary>Move the navigator to the first child element with the specified name, if it exists.</summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool MoveToChild(this ElementDefinitionNavigator nav, string name)
        {
            if (nav == null)
            {
                throw Error.ArgumentNull(nameof(nav));
            }
            if (nav.MoveToFirstChild())
            {
                do
                {
                    if (nav.PathName == name)
                    {
                        return(true);
                    }
                }while (nav.MoveToNext());
                nav.MoveToParent();
            }

            return(false);
        }
/*
 *      /// <summary>
 *      /// If the current element is a slice entry, then advance the navigator to the first associated named slice.
 *      /// Otherwise remain positioned at the current element.
 *      /// </summary>
 *      /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
 *      public static bool MoveToFirstSlice(this ElementDefinitionNavigator nav)
 *      {
 *          if (nav == null) { throw Error.ArgumentNull(nameof(nav)); }
 *          if (nav.Current == null) { throw Error.Argument(nameof(nav), "Cannot move navigator to previous slice. Current node is not set."); }
 *          if (nav.Current.Slicing != null)
 *          {
 *              var bm = nav.Bookmark();
 *              if (nav.MoveToNextSliceAtAnyLevel()) { return true; }
 *              nav.ReturnToBookmark(bm);
 *          }
 *          return false;
 *      }
 */

        /// <summary>
        /// Advance the navigator to the next slice in the current slice group and on the current slicing level.
        /// Skip any existing child elements and/or child reslicing constraints.
        /// Otherwise remain positioned at the current element.
        /// </summary>
        /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
        public static bool MoveToNextSlice(this ElementDefinitionNavigator nav)
        {
            if (nav == null)
            {
                throw Error.ArgumentNull(nameof(nav));
            }
            if (nav.Current == null)
            {
                throw Error.Argument(nameof(nav), "Cannot move navigator to next slice. Current node is not set.");
            }

            var bm = nav.Bookmark();

            var name               = nav.PathName;
            var startSliceName     = nav.Current.Name;
            var startBaseSliceName = ElementDefinitionNavigator.GetBaseSliceName(startSliceName);

            while (nav.MoveToNext(name))
            {
                var sliceName = nav.Current.Name;
                // Handle unnamed slices, eg. extensions
                if (startSliceName == null && sliceName == null)
                {
                    return(true);
                }

                if (ElementDefinitionNavigator.IsSiblingSliceOf(startSliceName, sliceName))
                {
                    return(true);
                }

                if (startBaseSliceName != null && sliceName.Length > startBaseSliceName.Length && !sliceName.StartsWith(startBaseSliceName))
                {
                    break;
                }
            }

            // No match, restore original position
            nav.ReturnToBookmark(bm);
            return(false);
        }
        private static void rebaseChildren(ElementDefinitionNavigator nav, string path, List <string> newPaths)
        {
            var bm = nav.Bookmark();

            if (nav.MoveToFirstChild())
            {
                do
                {
                    var newPath = path + "." + nav.Current.GetNameFromPath();

                    newPaths.Add(newPath);

                    if (nav.HasChildren)
                    {
                        rebaseChildren(nav, newPath, newPaths);
                    }
                }while (nav.MoveToNext());

                nav.ReturnToBookmark(bm);
            }
        }
        public static IEnumerable <Bookmark> Approach(this ElementDefinitionNavigator nav, string path)
        {
            if (nav == null)
            {
                throw Error.ArgumentNull(nameof(nav));
            }
            if (path == null)
            {
                throw Error.ArgumentNull(nameof(path));
            }

            var parts = path.Split('.');

            var bm = nav.Bookmark();

            nav.Reset();
            var result = locateChildren(nav, parts, partial: true);

            nav.ReturnToBookmark(bm);

            return(result);
        }
        /// <summary>
        /// Rewrites the Path's of the elements in a structure so they are based on the given path: the root
        /// of the given structure will become the given path, it's children will be relocated below that path
        /// </summary>
        /// <param name="elements">A list of element definitions that will be rebased on the path.</param>
        /// <param name="path">The path to rebase the structure on.</param>
        public static void Rebase(this IList <ElementDefinition> elements, string path)
        {
            var nav = new ElementDefinitionNavigator(elements);

            if (nav.MoveToFirstChild())
            {
                var newPaths = new List <string>()
                {
                    path
                };

                rebaseChildren(nav, path, newPaths);
                Debug.Assert(elements.Count == newPaths.Count);

                // Can only change the paths after navigating the tree, otherwise the
                // navigation functions (which are based on the paths) won't function correctly
                for (var i = 0; i < elements.Count; i++)
                {
                    elements[i].Path = newPaths[i];
                }
            }
        }
        public static bool AppendChild(this ElementDefinitionNavigator nav, ElementDefinition child)
        {
            var bm = nav.Bookmark();

            if (nav.MoveToFirstChild())
            {
                while (nav.MoveToNext())
                {
                    ;
                }
                var result = nav.InsertAfter(child);

                if (!result)
                {
                    nav.ReturnToBookmark(bm);
                }
                return(result);
            }
            else
            {
                return(nav.InsertFirstChild(child));
            }
        }
 public static string GetParentNameFromPath(this ElementDefinition defn)
 {
     return(ElementDefinitionNavigator.GetParentPath(defn.Path));
 }
 // [WMR 20160805] New
 public static bool IsRootElement(this ElementDefinition defn) => defn != null && ElementDefinitionNavigator.IsRootPath(defn.Path);
 public static bool IsExtension(this ElementDefinition defn) => defn != null && ElementDefinitionNavigator.IsExtensionPath(defn.Path);
 /// <summary>
 /// Advance the navigator to the immediately following slicing constraint in the current slice group, at any (re)slicing level.
 /// Skip any existing child elements.
 /// Otherwise remain positioned at the current element.
 /// </summary>
 /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
 public static bool MoveToNextSliceAtAnyLevel(this ElementDefinitionNavigator nav) => nav.MoveToNext(nav.PathName);
 /// <summary>Move the navigator to the first preceding or following sibling element with the specified name, if it exists.</summary>
 /// <returns><c>true</c> if succesful, <c>false</c> otherwise.</returns>
 public static bool MoveTo(this ElementDefinitionNavigator nav, string name)
 {
     // MoveNext method performs parameter validation
     return(MoveToNext(nav, name) || MoveToPrevious(nav, name));
 }