コード例 #1
0
        public ElementNavigator(ElementNavigator other)
        {
            if (other == null) throw Error.ArgumentNull("other");

            Elements = other.Elements.ToList();
            OrdinalPosition = other.OrdinalPosition;
        }
        public static ElementNavigator JumpToNameReference(this StructureDefinition elements, string nameReference)
        {
            var nav = new ElementNavigator(elements);

            //TODO: In the current DSTU1 base profiles, nameReference is actually a path, not a name (to Element.Name)
            //this is a problem, since when doing slicing, the path may no longer point to a single set of constraints
            //so, we need to (temporarily) watch out for this
            if (nameReference.Contains("."))
            {
                // An incorrectly used nameReference, containing a Path, not a name
                if (nav.JumpToFirst(nameReference))
                {
                    return(nav);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                if (nav.JumpToNameReference(nameReference))
                {
                    return(nav);
                }
                else
                {
                    return(null);
                }
            }
        }
コード例 #3
0
        public void Expand(Profile.ProfileStructureComponent structure)
        {
            if (structure.Differential == null) throw Error.Argument("structure", "structure does not contain a differential specification");
            var differential = structure.Differential;
            
            var baseStructure = _loader.LocateBaseStructure(structure.TypeElement);
            if (baseStructure == null) throw Error.InvalidOperation("Could not locate the base profile for type {0}", structure.TypeElement.ToString());
            if(baseStructure.Snapshot == null) throw Error.InvalidOperation("Base definition to use for expansion lacks a snapshot representation");

         //   var baseUri = StructureLoader.BuildBaseStructureUri(structure.TypeElement).ToString();

            var snapshot = (Profile.ConstraintComponent)baseStructure.Snapshot.DeepCopy();

            //DSTU1
            //snapshot.SetStructureForm(StructureForm.Snapshot);
            //snapshot.SetStructureBaseUri(baseUri.ToString());
            //mergeStructure(snapshot, differential);

            var fullDifferential = new DifferentialTreeConstructor(differential).MakeTree();

            var snapNav = new ElementNavigator(snapshot);
            snapNav.MoveToFirstChild();

            var diffNav = new ElementNavigator(fullDifferential);
            diffNav.MoveToFirstChild();

            merge(snapNav, diffNav);

            //TODO: Merge search params?

            snapNav.CommitChanges();
            structure.Snapshot = snapNav.Elements;
        }
コード例 #4
0
        public void Generate(StructureDefinition structure)
        {
            if (structure.Differential == null) throw Error.Argument("structure", "structure does not contain a differential specification");
            if (!structure.IsConstraint) throw Error.Argument("structure", "structure is not a constraint or extension");
            if(structure.Base == null) throw Error.Argument("structure", "structure is a constraint, but no base has been specified");

            var differential = structure.Differential;

            var baseStructure = _resolver.GetStructureDefinition(structure.Base);

            if (baseStructure == null) throw Error.InvalidOperation("Could not locate the base StructureDefinition for url " + structure.Base);
            if (baseStructure.Snapshot == null) throw Error.InvalidOperation("Snapshot generator required the base at {0} to have a snapshot representation", structure.Base);

            var snapshot = (StructureDefinition.SnapshotComponent)baseStructure.Snapshot.DeepCopy();
            generateBaseElements(snapshot.Element);
            var snapNav = new ElementNavigator(snapshot.Element);

            // Fill out the gaps (mostly missing parents) in the differential representation
            var fullDifferential = new DifferentialTreeConstructor(differential.Element).MakeTree();
            var diffNav = new ElementNavigator(fullDifferential);

            merge(snapNav, diffNav);
           
            structure.Snapshot = new StructureDefinition.SnapshotComponent() { Element = snapNav.ToListOfElements() };
        }
コード例 #5
0
        /// <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 BaseElementNavigator dest, ElementNavigator 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>
        /// 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="root">The structure that will be rebased on the path</param>
        /// <param name="path">The path to rebase the structure on</param>
        public static void Rebase(this StructureDefinition root, string path)
        {
            var nav = new ElementNavigator(root);

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

                rebaseChildren(nav, path, newPaths);

                var snapshot = root.Snapshot.Element;

                // 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 < root.Snapshot.Element.Count; i++)
                {
                    root.Snapshot.Element[i].Path = newPaths[i];
                }

                root.Differential = null;       // this is now invalid, because the snapshot has changed
            }
        }
コード例 #7
0
        public ElementNavigator(ElementNavigator other)
        {
            if (other == null) throw Error.ArgumentNull("other");

            setupElems(other._elements);
            OrdinalPosition = other.OrdinalPosition;
            Structure = other.Structure;
        }
コード例 #8
0
        public ElementNavigator(ElementNavigator other)
        {
            if (other == null)
            {
                throw Error.ArgumentNull("other");
            }

            Elements        = other.Elements.ToList();
            OrdinalPosition = other.OrdinalPosition;
        }
コード例 #9
0
        public static bool ExpandElement(this ElementNavigator nav, ArtifactResolver source)
        {
            if (source == null)
            {
                throw Error.ArgumentNull("source");
            }
            if (nav.Current == null)
            {
                throw Error.ArgumentNull("Navigator is not positioned on an element");
            }

            if (nav.HasChildren)
            {
                return(true);                     // already has children, we're not doing anything extra
            }
            var defn = nav.Current;

            if (!String.IsNullOrEmpty(defn.NameReference))
            {
                var sourceNav = new ElementNavigator(nav);
                var success   = sourceNav.JumpToNameReference(defn.NameReference);

                if (!success)
                {
                    throw Error.InvalidOperation("Trying to navigate down a node that has a nameReference of '{0}', which cannot be found in the StructureDefinition".FormatWith(defn.NameReference));
                }

                nav.CopyChildren(sourceNav);
            }
            else if (defn.Type != null && defn.Type.Count > 0)
            {
                if (defn.Type.Count > 1)
                {
                    throw new NotSupportedException("Element at path {0} has a choice of types, cannot expand".FormatWith(nav.Path));
                }
                else
                {
                    var coreType = source.GetStructureDefinitionForCoreType(defn.Type[0].Code);
                    if (coreType == null)
                    {
                        throw Error.NotSupported("Trying to navigate down a node that has a declared base type of '{0}', which is unknown".FormatWith(defn.Type[0].Code));
                    }
                    if (coreType.Snapshot == null)
                    {
                        throw Error.NotSupported("Found definition of base type '{0}', but is does not contain a snapshot representation".FormatWith(defn.Type[0].Code));
                    }

                    var sourceNav = new ElementNavigator(coreType.Snapshot.Element);
                    sourceNav.MoveToFirstChild();
                    nav.CopyChildren(sourceNav);
                }
            }

            return(true);
        }
コード例 #10
0
        public ElementNavigator(ElementNavigator other)
        {
            if (other == null)
            {
                throw Error.ArgumentNull("other");
            }

            setupElems(other._elements);
            OrdinalPosition = other.OrdinalPosition;
            Structure       = other.Structure;
        }
コード例 #11
0
        private void merge(ElementNavigator snapNav, ElementNavigator diffNav)
        {
            var snapPos = snapNav.Bookmark();
            var diffPos = diffNav.Bookmark();

            try
            {
                var matches = (new ElementMatcher()).Match(snapNav, diffNav);

                //Debug.WriteLine("Matches for children of {0}".FormatWith(snapNav.Path));
                //matches.DumpMatches(snapNav, diffNav);

                foreach (var match in matches)
                {
                    if (!snapNav.ReturnToBookmark(match.BaseBookmark))
                        throw Error.InvalidOperation("Internal merging error: bookmark {0} in snap is no longer available", match.BaseBookmark);
                    if (!diffNav.ReturnToBookmark(match.DiffBookmark))
                        throw Error.InvalidOperation("Internal merging error: bookmark {0} in diff is no longer available", match.DiffBookmark);

                    if (match.Action == ElementMatcher.MatchAction.Add)
                    {
                        // TODO: move this logic to matcher, the Add should point to the last slice where
                        // the new slice will be added after.

                        // Find last entry in slice to add to the end
                        var current = snapNav.Path;
                        while (snapNav.Current.Path == current && snapNav.MoveToNext()) ;
                        snapNav.MoveToPrevious();       // take one step back...
                        var dest = snapNav.Bookmark();
                        snapNav.ReturnToBookmark(match.BaseBookmark);
                        snapNav.DuplicateAfter(dest);
                        markChange(snapNav.Current);

                        mergeElement(snapNav, diffNav);
                        snapNav.Current.Slicing = null;         // Probably not good enough...
                    }
                    else if (match.Action == ElementMatcher.MatchAction.Merge)
                    {
                        mergeElement(snapNav, diffNav);
                    }
                    else if (match.Action == ElementMatcher.MatchAction.Slice)
                    {
                        makeSlice(snapNav, diffNav);
                    }
                }
            }
            finally
            {
                snapNav.ReturnToBookmark(snapPos);
                diffNav.ReturnToBookmark(diffPos);
            }
        }
コード例 #12
0
        public XElement generateStructureTable(Profile.ProfileStructureComponent structure, bool diff, Profile profile) 
        {
            HierarchicalTableGenerator gen = new HierarchicalTableGenerator(_pkp);
            var model = TableModel.CreateNormalTable();

            // List<Profile.ElementComponent> list = diff ? structure.getDifferential().getElement() : structure.getSnapshot().getElement();   DSTU2
            var list = structure.Element;
            var nav = new ElementNavigator(structure);
            nav.MoveToFirstChild();
    
            genElement(gen, model.Rows, nav, profile, true);
            return gen.generate(model);
        }
コード例 #13
0
        private void merge(ElementNavigator snap, ElementNavigator diff)
        {
            (new ElementDefnMerger(_markChanges)).Merge(snap.Current, diff.Current);

            // If there are children, move into them, and recursively merge them
            if (diff.MoveToFirstChild())
            {
                if (!snap.HasChildren)
                {
                    // The differential moves into an element that has no children in the base.
                    // This is allowable if the base's element has a nameReference or a TypeRef,
                    // in which case needs to be expanded before we can move to the path indicated
                    // by the differential

                    if (snap.Current.Type.Count > 1)
                        throw new NotSupportedException("Differential has a constraint on a choice element {0}, but does so without using a type slice".FormatWith(diff.Path));

                    expandBaseElement(snap, diff);
                }

                // Due to how MoveToFirstChild() works, we have to move to the first matching *child*
                // when entering the loop for the first time, after that we can look for the next
                // matching *sibling*.
                bool firstEntry = true;

                do
                {
                    if ((firstEntry && !snap.MoveToChild(diff.PathName)) ||
                        (!firstEntry && !snap.MoveTo(diff.PathName)) ) // HACK: I don't think it should be allowed for a diff to list constraints in the wrong order...
                    {
                        throw Error.InvalidOperation("Differential has a constraint for path '{0}', which does not exist in its base", diff.Path);
                    }
                    firstEntry = false;

                    // Child found in both, merge them
                    if (countChildNameRepeats(diff) > 1 || diff.Current.IsExtension())
                    {
                        // The child in the diff repeats or we recognize it as an extension slice -> we're on the first element of a slice!
                        mergeSlice(snap, diff);
                    }
                    else
                        merge(snap, diff);
                }
                while (diff.MoveToNext());

                // After the merge, return the diff and snapho back to their original position
                diff.MoveToParent();
                snap.MoveToParent();
            }
        }
コード例 #14
0
        public XElement generateStructureTable(String defFile, Profile.ProfileStructureComponent structure, bool diff, String imageFolder, 
                    bool inlineGraphics, Profile profile, string profileUrl, String profileBaseFileName) 
        {
            HierarchicalTableGenerator gen = new HierarchicalTableGenerator(imageFolder, inlineGraphics);
            TableModel model = gen.initNormalTable();

            // List<Profile.ElementComponent> list = diff ? structure.getDifferential().getElement() : structure.getSnapshot().getElement();   DSTU2
            var list = structure.Element;
            var nav = new ElementNavigator(structure);
            nav.MoveToFirstChild();
    
            genElement(defFile == null ? null : defFile+"#"+structure.Name+".", gen, model.getRows(), nav, profile, diff, profileUrl, profileBaseFileName);
            return gen.generate(model);
        }
コード例 #15
0
ファイル: ElementMatcher.cs プロジェクト: tiloc/fhir-net-api
        /// <summary>
        /// Will match up the children of the current element in diffNav to the children of the element in snapNav.
        /// </summary>
        /// <param name="snapNav"></param>
        /// <param name="diffNav"></param>
        /// <returns>Returns a list of Bookmark combinations, the first bookmark pointing to an element in the base,
        /// the second a bookmark in the diff that matches the bookmark in the base.</returns>
        /// <remarks>Will match slices to base elements, re-sliced slices to slices and type-slice shorthands to choie elements.
        /// Note that this function may expand snapNav when it encounters paths in the differential that move into the complex types
        /// of one of snap's elements.  (NO NEED, it just has to match direct children, not deeper)
        /// This function assumes the differential is not sparse: it must have parent nodes for all child constraint paths.
        /// </remarks>
        public List<MatchInfo> Match(ElementNavigator snapNav, ElementNavigator diffNav)
        {
            if (!snapNav.HasChildren) throw Error.Argument("snapNav", "Cannot match base to diff: element '{0}' in snap has no children".FormatWith(snapNav.PathName));
            if (!diffNav.HasChildren) throw Error.Argument("diffNav", "Cannot match base to diff: element '{0}' in diff has no children".FormatWith(diffNav.PathName));

            // These bookmarks are used only in the finally {} to make sure we don't alter the position of the navs when leaving the merger
            var baseStartBM = snapNav.Bookmark();
            var diffStartBM = diffNav.Bookmark();

            snapNav.MoveToFirstChild();
            diffNav.MoveToFirstChild();

            var choiceNames = listChoiceElements(snapNav);

            var result = new List<MatchInfo>();

            try
            {
                do
                {
                    // First, match directly -> try to find the child in base with the same name as the path in the diff
                    if (snapNav.PathName != diffNav.PathName && !snapNav.MoveToNext(diffNav.PathName))
                    {
                        // Not found, maybe this is a type slice shorthand, look if we have a matching choice prefix in snap
                        var typeSliceShorthand = diffNav.PathName;

                        // Try to match nameXXXXX to name[x]
                        var matchingChoice = choiceNames.SingleOrDefault(prefix => isPossibleTypeSlice(prefix, typeSliceShorthand));

                        if (matchingChoice != null)
                            snapNav.MoveToNext(matchingChoice);
                        else
                            throw Error.InvalidOperation("Differential has a constraint for path '{0}', which does not exist in its base".FormatWith(diffNav.Path));
                    }

                    result.AddRange(constructMatch(snapNav, diffNav));
                }
                while (diffNav.MoveToNext());
            }
            finally
            {
                snapNav.ReturnToBookmark(baseStartBM);
                diffNav.ReturnToBookmark(diffStartBM);
            }

            return result;
        }
コード例 #16
0
ファイル: ElementMatcher.cs プロジェクト: tiloc/fhir-net-api
        public static void DumpMatches(this IEnumerable<ElementMatcher.MatchInfo> matches, ElementNavigator snapNav, ElementNavigator diffNav)
        {
            var sbm = snapNav.Bookmark();
            var dbm = diffNav.Bookmark();

            foreach(var match in matches)
            {
                if (!snapNav.ReturnToBookmark(match.BaseBookmark) || !diffNav.ReturnToBookmark(match.DiffBookmark))
                    throw Error.InvalidOperation("Found unreachable bookmark in matches");

                var bPos = snapNav.Path + "[{0}]".FormatWith(snapNav.OrdinalPosition);
                var dPos = diffNav.Path + "[{0}]".FormatWith(diffNav.OrdinalPosition);
                Debug.WriteLine("B:{0} <--{1}--> D:{2}".FormatWith(bPos, match.Action.ToString(), dPos));
            }

            snapNav.ReturnToBookmark(sbm);
            diffNav.ReturnToBookmark(dbm);
        }
コード例 #17
0
        /// <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="root">The structure that will be rebased on the path</param>
        /// <param name="path">The path to rebase the structure on</param>
        public static void Rebase(this IElementList root, string path)
        {
            var nav = new ElementNavigator(root.Element);

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

                rebaseChildren(nav, path, newPaths);

                var snapshot = root.Element;

                // 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 < root.Element.Count; i++)
                    root.Element[i].Path = newPaths[i];
            }
        }
コード例 #18
0
        //private static void mergeStructure(Profile.ConstraintComponent snapshot, Profile.ConstraintComponent differential)
        //{
        //    if (differential.Name != null) snapshot.Name = differential.Name;
        //    if (differential.Publish != null) snapshot.Publish = differential.Publish;
        //    if (differential.Purpose != null) snapshot.Purpose = differential.Purpose;
        //}


        private void merge(ElementNavigator snap, ElementNavigator diff)
        {
            mergeElementAttributes(snap.Current, diff.Current);

            // If there are children, move into them, and recursively merge them
            if (diff.MoveToFirstChild())
            {
                if (!snap.HasChildren)
                {
                    // The differential moves into an element that has no children in the base.
                    // This is allowable if the base's element has a nameReference or a TypeRef,
                    // in which case needs to be expanded before we can move to the path indicated
                    // by the differential
                    expandBaseElement(snap, diff);
                }

                // Due to how MoveToFirstChild() works, we have to move to the first matching *child*
                // when entering the loop for the first time, after that we can look for the next
                // matching *sibling*.
                bool firstEntry = true;

                do
                {
                    if( (firstEntry && !snap.MoveToChild(diff.PathName)) ||
                        (!firstEntry && !snap.MoveToNext(diff.PathName)) )
                             throw Error.InvalidOperation("Differential has a constraint for path '{0}', which does not exist in its base", diff.PathName);                   
                    firstEntry = false;

                    // Child found in both, merge them
                    if (countChildNameRepeats(diff) > 1 || diff.Current.IsExtension())
                    {
                        // The child in the diff repeats or we recognize it as an extension slice -> we're on the first element of a slice!
                        mergeSlice(snap, diff); 
                    }
                    else
                        merge(snap, diff);
                }
                while (diff.MoveToNext());

                // After the merge, return the diff and snapho back to their original position
                diff.MoveToParent();
                snap.MoveToParent();
            }
        }
        /// <summary>
        /// Insert the children of the current source node under the node pointed to by the destination.
        /// </summary>
        /// <param name="dest"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool CopyChildren(this BaseElementNavigator dest, ElementNavigator 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);
        }
コード例 #20
0
        /// <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="root">The structure that will be rebased on the path</param>
        /// <param name="path">The path to rebase the structure on</param>
        public static void Rebase(this StructureDefinition root, string path)
        {
            var nav = new ElementNavigator(root);

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

                rebaseChildren(nav, path, newPaths);

                var snapshot = root.Snapshot.Element;

                // 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 < root.Snapshot.Element.Count; i++)
                    root.Snapshot.Element[i].Path = newPaths[i];

                root.Differential = null;       // this is now invalid, because the snapshot has changed
            }
        }
コード例 #21
0
        /// <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="root">The structure that will be rebased on the path</param>
        /// <param name="path">The path to rebase the structure on</param>
        public static void Rebase(this IElementList root, string path)
        {
            var nav = new ElementNavigator(root.Element);

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

                rebaseChildren(nav, path, newPaths);

                var snapshot = root.Element;

                // 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 < root.Element.Count; i++)
                {
                    root.Element[i].Path = newPaths[i];
                }
            }
        }
コード例 #22
0
        public static ElementNavigator JumpToNameReference(this StructureDefinition elements, string nameReference)
        {
            var nav = new ElementNavigator(elements);

            //TODO: In the current DSTU1 base profiles, nameReference is actually a path, not a name (to Element.Name)
            //this is a problem, since when doing slicing, the path may no longer point to a single set of constraints
            //so, we need to (temporarily) watch out for this
            if (nameReference.Contains("."))
            {
                // An incorrectly used nameReference, containing a Path, not a name
                if (nav.JumpToFirst(nameReference))
                    return nav;
                else
                    return null;
            }
            else
            {
                if (nav.JumpToNameReference(nameReference))
                    return nav;
                else
                    return null;
            }                

        }
コード例 #23
0
        private static int countChildNameRepeats(ElementNavigator diff)
        {
            //TODO: We use this function to determine whether an element is sliced...doing this by counting repeats of elements
            //in the diff. However, when reslicing, the diff doesn't need to have repeating elements, and you have to derive from the
            //base (snapshot) that the element is sliced.

            var repeats = 1;

            var currentPath = diff.PathName;
            var bm = diff.Bookmark();
            while (diff.MoveToNext())
            {
                // check whether the next sibling in the differential has the same name,
                // that means we're looking at a slice
                if (diff.PathName == currentPath)
                    repeats++;
                else
                    break;
            }

            diff.ReturnToBookmark(bm);
            return repeats;
        }
コード例 #24
0
        public static bool ExpandElement(this ElementNavigator nav, ArtifactResolver source)
        {
            if (source == null) throw Error.ArgumentNull("source");
            if (nav.Current == null) throw Error.ArgumentNull("Navigator is not positioned on an element");

            if (nav.HasChildren) return true;     // already has children, we're not doing anything extra

            var defn = nav.Current;

            if (!String.IsNullOrEmpty(defn.NameReference))
            {
                var sourceNav = new ElementNavigator(nav);
                var success = sourceNav.JumpToNameReference(defn.NameReference);

                if(!success)
                    throw Error.InvalidOperation("Trying to navigate down a node that has a nameReference of '{0}', which cannot be found in the StructureDefinition".FormatWith(defn.NameReference));

                nav.CopyChildren(sourceNav);
            }
            else if (defn.Type != null && defn.Type.Count > 0)
            {
                if (defn.Type.Count > 1)
                    throw new NotSupportedException("Element at path {0} has a choice of types, cannot expand".FormatWith(nav.Path));
                else
                {
                    var coreType = source.GetStructureDefinitionForCoreType(defn.Type[0].Code);
                    if (coreType == null) throw Error.NotSupported("Trying to navigate down a node that has a declared base type of '{0}', which is unknown".FormatWith(defn.Type[0].Code));
                    if (coreType.Snapshot == null) throw Error.NotSupported("Found definition of base type '{0}', but is does not contain a snapshot representation".FormatWith(defn.Type[0].Code));

                    var sourceNav = new ElementNavigator(coreType.Snapshot.Element);
                    sourceNav.MoveToFirstChild();
                    nav.CopyChildren(sourceNav);
                }
            }

            return true;
        }
コード例 #25
0
ファイル: ElementMatcher.cs プロジェクト: tiloc/fhir-net-api
        private static List<MatchInfo> constructSliceMatch(ElementNavigator snapNav, ElementNavigator diffNav)
        {
            var result = new List<MatchInfo>();

            var bm = snapNav.Bookmark();
            var diffName = diffNav.PathName;
            bool baseIsSliced = snapNav.Current.Slicing != null;
            bool diffIsSliced = diffNav.Current.IsExtension() || nextChildName(diffNav) == diffNav.PathName;

            if (baseIsSliced)
                throw Error.NotSupported("Cannot yet handle re-slicing found at diff {0}".FormatWith(diffNav.Path));

            // For the first entries with explicit slicing information (or implicit if this is an extension),
            // generate a match between the base's unsliced element and the first entry in the diff
            if(diffNav.Current.Slicing != null || diffNav.Current.IsExtension() )
            {
                // Differential has information for the slicing entry
                result.Add(new MatchInfo()
                {
                    BaseBookmark = bm,
                    DiffBookmark = diffNav.Bookmark(),
                    Action = MatchAction.Slice
                });

                if(!diffNav.Current.IsExtension())
                {
                    if (!diffNav.MoveToNext())
                        throw Error.InvalidOperation("Differential has a slicing entry {0}, but no first actual slice", diffNav.Path);
                }
            }

            // Then, generate a match between the base's unsliced element and the slicing entries in the diff
            // Note that the first entry may serve a double role and have to result matches (one for the constraints, one as a slicing entry)
            do
            {
                result.Add(new MatchInfo()
                {
                    BaseBookmark = bm,
                    DiffBookmark = diffNav.Bookmark(),
                    Action = MatchAction.Add
                });
            } while (nextChildName(diffNav) == diffName && diffNav.MoveToNext());  // Warning: Subtle use of short-cut evaluation

            return result;
        }
コード例 #26
0
        private void expandBaseElement(ElementNavigator snap, ElementNavigator diff)
        {
            snap.ExpandElement(_loader);

            if (!snap.HasChildren)
            {
                // Snapshot's element turns out not to be expandable, so we can't move to the desired path
                throw Error.InvalidOperation("Differential has nested constraints for node {0}, but this is a leaf node in base", diff.Path);
            }
        }
コード例 #27
0
        private void mergeSlice(ElementNavigator snap, ElementNavigator diff)
        {
            // diff is now located at the first repeat of a slice, which is (possibly) the slice entry
            // snap is located at the base definition of the element that will become sliced. But snap is not yet sliced.

            // Before we start, is the base element sliceable?
            if (!snap.Current.IsRepeating() && !isSlicedToOne(diff.Current))
                throw Error.InvalidOperation("The slicing entry in the differential at {0} indicates an unbounded slice, but the base element is not a repeating element",
                   diff.Current.Path);
           
            Profile.ElementComponent slicingEntry;

            // Yes, so, first, add the slicing entry to the snapshot. 
            if (diff.Current.Slicing != null)
            {
                slicingEntry = createSliceEntry(snap.Current, diff.Current);
                snap.InsertBefore(slicingEntry);

                if (!diff.MoveToNext(diff.PathName))
                    throw Error.InvalidOperation("Slicing has no elements beyond the slicing entry");  // currently impossible to happen
            }
            else
            {
                // Mmmm....no slicing entry in the differential. This is only alloweable for extension slices, as a shorthand notation.                 
                if (!snap.Current.IsExtension())
                    throw Error.InvalidOperation("The slice group at {0} does not start with a slice entry element", diff.Current.Path);

                // In this case we insert a "prefab" extension slice.
                slicingEntry = createExtensionSlicingEntry(snap.Path, snap.Current);
                snap.InsertBefore(slicingEntry);
            }

            snap.MoveToNext();  

            // The differential and the snapshot are now both positioned on the first "real" slicing content element
            // Start by duplicating the current unsliced base definition as many times as we have slices, so we can
            // update these copies for each slice.
            var numSlices = countChildNameRepeats(diff);
            for (var count = 0; count < numSlices-1; count++) snap.Duplicate();

            var slicingName = snap.PathName;

            do
            {
                merge(snap, diff);
            }
            while (diff.MoveToNext(slicingName) && snap.MoveToNext(slicingName));

            //if (slicingEntry.Slicing.Rules != Profile.SlicingRules.Closed)
            //{
            //    // Slices that are open in some form need to repeat the original "base" definition,
            //    // so that the open slices have a place to "fit in"
            //    snap.InsertAfter((Profile.ElementComponent)slicingTemplate.DeepCopy());
            //}

            //TODO: update/check the slice entry's min/max property to match what we've found in the slice group
        }
コード例 #28
0
        private void genElement(HierarchicalTableGenerator gen, List<Row> rows, ElementNavigator nav, 
                    Profile profile, bool showMissing)
        {
            var element = nav.Current;

            if(onlyInformationIsMapping(nav.Structure.Element, element)) return;  // we don't even show it in this case

            Row row = new Row();
            row.setAnchor(element.Path);
            String s = element.GetNameFromPath();

            bool hasDef = element.Definition != null;
            bool ext = false;
    
            if (s == "extension" || s == "modifierExtension")
            { 
                row.setIcon("icon_extension_simple.png");
                ext = true;
            }
            else if (!hasDef || element.Definition.Type == null || element.Definition.Type.Count == 0)
            {
                row.setIcon("icon_element.gif");
            }
            else if (hasDef && element.Definition.Type.Count > 1)
            {
                if (allTypesAre(element.Definition.Type, "ResourceReference"))
                    row.setIcon("icon_reference.png");
                else
                    row.setIcon("icon_choice.gif");
            }
            else if (hasDef && element.Definition.Type[0].Code.StartsWith("@"))
            {
                //TODO: That's not a legal code, will this ever appear?
                //I am pretty sure this depends on ElementDefn.NameReference
                row.setIcon("icon_reuse.png");
            }
            else if (hasDef && _pkp.isPrimitive(element.Definition.Type[0].Code))
                row.setIcon("icon_primitive.png");
            else if (hasDef && _pkp.isReference(element.Definition.Type[0].Code))
                row.setIcon("icon_reference.png");
            else if (hasDef && _pkp.isDataType(element.Definition.Type[0].Code))
                row.setIcon("icon_datatype.gif");
            else
                row.setIcon("icon_resource.png");


            var reference = _pkp.GetLinkForElementDefinition(nav.Structure, profile, element);
            //String reference = defPath == null ? null : defPath + makePathLink(element);
            UnusedTracker used = new UnusedTracker();
            used.used = true;
            
            Cell left = new Cell(null, reference, s, !hasDef ? null : element.Definition.Formal, null);
            row.getCells().Add(left);
    
            if (ext)
            {
                // If this element (row) in the table is an extension...
                if (element.Definition != null && element.Definition.Type.Count == 1 && element.Definition.Type[0].Profile != null) 
                {
                    Profile.ProfileExtensionDefnComponent extDefn = _pkp.getExtensionDefinition(profile, element.Definition.Type[0].Profile);
        
                    if (extDefn == null) 
                    {
                        row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null));
                        row.getCells().Add(new Cell(null, null, "?? "+element.Definition.Type[0].Profile, null, null));
                        generateDescription(gen, row, element, null, used.used, element.Definition.Type[0].Profile, profile);
                    }
                    else 
                    {
                        row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, extDefn.Definition, used), null, null));
                        genTypes(gen, row, extDefn.Definition, profile);
                        generateDescription(gen, row, element, extDefn.Definition, used.used, element.Definition.Type[0].Profile, profile);
                    } 
                }
                else if (element.Definition != null) 
                {
                    row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null));
                    genTypes(gen, row, element.Definition, profile);
                    generateDescription(gen, row, element, null, used.used, null, profile);
                } 
                else 
                {
                    row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null));
                    row.getCells().Add(new Cell());
                    generateDescription(gen, row, element, null, used.used, null, profile);
                }
            } 
            else 
            {
                row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null));
                
                if (element.Definition != null)
                    genTypes(gen, row, element.Definition, profile);
                else
                    row.getCells().Add(new Cell());
        
                generateDescription(gen, row, element, null, used.used, null, profile);
            }
      
            if (element.Slicing != null) 
            {
                row.setIcon("icon_slice.png");
                row.getCells()[2].getPieces().Clear();
        
                foreach (Cell cell in row.getCells())
                    foreach (Piece p in cell.getPieces())
                    {
                        p.addStyle("font-style: italic");
                    }        
            }

            if (used.used || showMissing)
                rows.Add(row);
      
            if (!used.used) 
            {
                foreach (Cell cell in row.getCells())
                foreach (Piece p in cell.getPieces()) 
                {
                    p.setStyle("text-decoration:line-through");
                    p.setReference(null);
                }
            } 
            else
            {
                if (nav.MoveToFirstChild())
                {
                    do
                    {
                        genElement(gen, row.getSubRows(), nav, profile, showMissing);
                    } while (nav.MoveToNext());

                   nav.MoveToParent();
                }
            }
        }
コード例 #29
0
        private void mergeElement(ElementNavigator snap, ElementNavigator diff)
        {
            (new ElementDefnMerger(_markChanges)).Merge(snap.Current, diff.Current);

            if (diff.HasChildren)
            {
                if (!snap.HasChildren)
                {
                    // The differential moves into an element that has no children in the base.
                    // This is allowable if the base's element has a nameReference or a TypeRef,
                    // in which case needs to be expanded before we can move to the path indicated
                    // by the differential

                    // Note that since we merged the parent, a (shorthand) typeslice will already
                    // have reduced the numer of types to 1. Still, if you don't do that, we cannot
                    // accept constraints on children, need to select a single type first...
                    if (snap.Current.Type.Count > 1)
                        throw new NotSupportedException("Differential has a constraint on a choice element {0}, but does so without using a type slice".FormatWith(diff.Path));

                    ExpandElement(snap, _resolver);

                    if (!snap.HasChildren)
                    {
                        // Snapshot's element turns out not to be expandable, so we can't move to the desired path
                        throw Error.InvalidOperation("Differential has nested constraints for node {0}, but this is a leaf node in base", diff.Path);
                    }
                }

                // Now, recursively merge the children
                merge(snap, diff);
            }
        }
コード例 #30
0
        private void makeSlice(ElementNavigator snap, ElementNavigator diff)
        {
            // diff is now located at the first repeat of a slice, which is normally the slice entry (Extension slices need
            // not have a slicing entry)
            // snap is located at the base definition of the element that will become sliced. But snap is not yet sliced.

            // Before we start, is the base element sliceable?
            if (!snap.Current.IsRepeating() && !snap.Current.IsChoice())
                throw Error.InvalidOperation("The slicing entry in the differential at {0} indicates an slice, but the base element is not a repeating or choice element",
                   diff.Current.Path);

            ElementDefinition slicingEntry = diff.Current;

            //Mmmm....no slicing entry in the differential. This is only alloweable for extension slices, as a shorthand notation.
            if (slicingEntry.Slicing == null)
            {
                if (slicingEntry.IsExtension())
                {
                    // In this case we create a "prefab" extension slice (with just slincing info)
                    // that's simply merged with the original element in base
                    slicingEntry = createExtensionSlicingEntry();
                }
                else
                {
                    throw Error.InvalidOperation("The slice group at {0} does not start with a slice entry element", diff.Current.Path);
                }
            }

            (new ElementDefnMerger(_markChanges)).Merge(snap.Current, slicingEntry);

            ////TODO: update / check the slice entry's min/max property to match what we've found in the slice group
        }
コード例 #31
0
ファイル: ElementMatcher.cs プロジェクト: tiloc/fhir-net-api
        /// <summary>
        /// Creates matches between the elements pointed to by snapNav and diffNav. After returning, both
        /// navs will be located on the last element that was matched (e.g. in a slicing group)
        /// </summary>
        /// <param name="snapNav"></param>
        /// <param name="diffNav"></param>
        /// <returns></returns>
        private static List<MatchInfo> constructMatch(ElementNavigator snapNav, ElementNavigator diffNav)
        {
            var match = new MatchInfo() { BaseBookmark = snapNav.Bookmark(), DiffBookmark = diffNav.Bookmark() };

            bool baseIsSliced = snapNav.Current.Slicing != null;
            bool diffIsSliced = diffNav.Current.IsExtension() || nextChildName(diffNav) == diffNav.PathName;

            // Easiest case - one to one match, without slicing involved
            if (!baseIsSliced && !diffIsSliced)
            {
                match.Action = MatchAction.Merge;

                return new List<MatchInfo>() { match };
            }

            // Check whether this is a type-slice shorthand - only the most common usecase
            // is supported for this case, otherwise us a normal type-slice
            // See also gForge issues #8974 and #8973
            if (isPossibleTypeSlice(snapNav.PathName, diffNav.PathName))
            {
                if (baseIsSliced) throw Error.NotSupported("Using a slicing shorthand ({0}) is not supported for re-slicing".FormatWith(diffNav.Path));
                if (diffIsSliced) throw Error.NotSupported("Using a slicing shorthand ({0}) can only be used to introduce a single slice".FormatWith(diffNav.Path));

                match.Action = MatchAction.Merge;
                return new List<MatchInfo>() { match };
            }

            // Else, this is a slice match - process it separately
            return constructSliceMatch(snapNav, diffNav);
        }
コード例 #32
0
 public static string GetParentNameFromPath(this ElementDefinition element)
 {
     return(ElementNavigator.GetParentPath(element.Path));
 }
コード例 #33
0
ファイル: ElementMatcher.cs プロジェクト: tiloc/fhir-net-api
        /// <summary>
        /// List all names of nodes in the current navigator that are choice ('[x]') elements
        /// </summary>
        /// <param name="snapNav"></param>
        /// <returns></returns>
        private List<string> listChoiceElements(ElementNavigator snapNav)
        {
            var bm = snapNav.Bookmark();
            var result = new List<string>();

            do
            {
                if (snapNav.Current.IsChoice()) result.Add(snapNav.PathName);
            } while (snapNav.MoveToNext());

            snapNav.ReturnToBookmark(bm);

            return result;
        }
コード例 #34
0
        private static int countChildNameRepeats(ElementNavigator diff)
        {
            var repeats = 1;

            var currentPath = diff.PathName;
            var bm = diff.Bookmark();
            while(diff.MoveToNext())
            {
                // check whether the next sibling in the differential has the same name,
                // that means we're looking at a slice
                if (diff.PathName == currentPath)
                    repeats++;
                else
                    break;
            }

            diff.ReturnToBookmark(bm);
            return repeats;
        }
コード例 #35
0
ファイル: ElementMatcher.cs プロジェクト: tiloc/fhir-net-api
        private static string nextChildName(ElementNavigator nav)
        {
            string result = null;

            if (nav.MoveToNext())
            {
                result = nav.PathName;
                nav.MoveToPrevious();
            }

            return result;
        }