/// <summary> /// Creates a differential structure with all "skipped" parents filled in. /// </summary> /// <param name="differential"></param> /// <returns>The full tree structure representing the differential</returns> /// <remarks>This operation will not touch the source differential, but instead will return a new structure.</remarks> public Profile.ConstraintComponent MakeTree() { var diff = (Profile.ConstraintComponent)_source.DeepCopy(); // We're going to modify the differential if (diff.Element == null || diff.Element.Count == 0) return diff; // nothing to do var index = 0; var elements = diff.Element; while (index < elements.Count) { var thisPath = elements[index].Path; var prevPath = index > 0 ? elements[index - 1].Path : String.Empty; if (thisPath.IndexOf('.') == -1) { // I am a root node, just one segment of path, I need to be the first element if (index != 0) throw Error.InvalidOperation("Differential has multiple roots"); // Else, I am fine, proceed index++; } else if (ElementNavigator.IsSibling(thisPath, prevPath) || ElementNavigator.IsDirectChildPath(prevPath, thisPath)) { // The previous path is a sibling, or my direct parent, so everything is alright, proceed to next node index++; } else { var parentPath = ElementNavigator.GetParentPath(thisPath); if (prevPath == String.Empty || !prevPath.StartsWith(parentPath + ".")) { // We're missing a path part, insert an empty parent var parentElement = new Profile.ElementComponent() { Path = parentPath }; elements.Insert(index, parentElement); // Now, we're not sure this parent has parents, so proceed by checking the parent we have just inserted // so -> index is untouched } else { // So, my predecessor an I share ancestry, of which I am sure it has been inserted by this algorithm // before because of my predecessor, so we're fine. index++; } } } return diff; }
public void TestChildAlterations() { var nav = createTestNav(); var newENode = new Profile.ElementComponent() { Path = "X.Y.E" }; var newC3Node = new Profile.ElementComponent() { Path = "X.Y.C3" }; Assert.IsTrue(nav.JumpToFirst("A.B.C1.D")); Assert.IsTrue(nav.InsertFirstChild(newENode)); Assert.AreEqual(8,nav.OrdinalPosition); Assert.IsTrue(nav.MoveToParent()); Assert.AreEqual("A.B.C1.D", nav.Path); Assert.IsTrue(nav.MoveToFirstChild()); Assert.IsTrue(nav.Delete()); Assert.AreEqual("A.B.C1.D", nav.Path); // should have moved back to parent (single child deleted) Assert.IsTrue(nav.JumpToFirst("A.D")); Assert.IsTrue(nav.InsertFirstChild(newENode)); Assert.AreEqual(9,nav.OrdinalPosition); Assert.IsTrue(nav.MoveToParent()); Assert.AreEqual("A.D", nav.Path); Assert.IsTrue(nav.MoveToFirstChild()); Assert.IsTrue(nav.Delete()); Assert.AreEqual("A.D", nav.Path); // should have moved back to parent (single child deleted) nav.Reset(); Assert.IsTrue(nav.MoveToFirstChild()); Assert.IsTrue(nav.MoveToFirstChild()); // A.B Assert.IsTrue(nav.AppendChild(newC3Node)); Assert.AreEqual("A.B.C3",nav.Path); Assert.AreEqual(4, nav.OrdinalPosition); Assert.IsTrue(nav.Delete()); Assert.AreEqual(3, nav.OrdinalPosition); Assert.IsTrue(nav.MoveToPrevious()); // A.B.C1 Assert.IsTrue(nav.Delete()); Assert.AreEqual(2, nav.OrdinalPosition); Assert.IsTrue(nav.Delete()); Assert.AreEqual(1, nav.OrdinalPosition); // Moved back to parent? }
public void TestSiblingAlterations() { var nav = createTestNav(); var newCNode = new Profile.ElementComponent() { Path = "X.C" }; Assert.AreEqual(9, nav.Count); nav.MoveToFirstChild(); Assert.IsTrue(nav.MoveToChild("D")); Assert.IsTrue(nav.InsertBefore(newCNode)); Assert.AreEqual("A.C", nav.Path); Assert.AreEqual(8, nav.OrdinalPosition); Assert.AreEqual(10, nav.Count); Assert.IsTrue(nav.Delete()); // delete new "C" node we just created Assert.AreEqual(8, nav.OrdinalPosition); Assert.AreEqual(9, nav.Count); Assert.IsTrue(nav.MoveToPrevious()); // 3rd "A.B" node Assert.IsTrue(nav.InsertAfter(newCNode)); Assert.AreEqual("A.C", nav.Path); Assert.AreEqual(8, nav.OrdinalPosition); Assert.AreEqual(10, nav.Count); Assert.IsTrue(nav.Delete()); // delete new "C" node we just created Assert.AreEqual(8, nav.OrdinalPosition); Assert.AreEqual(9, nav.Count); Assert.IsTrue(nav.InsertAfter(newCNode)); Assert.AreEqual("A.C", nav.Path); Assert.AreEqual(9, nav.OrdinalPosition); Assert.AreEqual(10, nav.Count); Assert.IsTrue(nav.Delete()); // delete new "C" node we just created Assert.AreEqual(8, nav.OrdinalPosition); Assert.AreEqual(9, nav.Count); Assert.IsTrue(nav.MoveToParent()); Assert.IsTrue(nav.MoveToFirstChild()); Assert.IsTrue(nav.InsertBefore(newCNode)); Assert.AreEqual("A.C", nav.Path); Assert.AreEqual(1, nav.OrdinalPosition); Assert.AreEqual(10, nav.Count); }
private Profile.ElementComponent createSliceEntry(Profile.ElementComponent baseDefn, Profile.ElementComponent diff) { var slicingEntry = new Profile.ElementComponent(); slicingEntry.PathElement = (FhirString)baseDefn.PathElement.DeepCopy(); if (diff.Name != null) slicingEntry.NameElement = (FhirString)diff.NameElement.DeepCopy(); if (diff.Slicing != null) slicingEntry.Slicing = (Profile.ElementSlicingComponent)diff.Slicing.DeepCopy(); slicingEntry.Definition = (Profile.ElementDefinitionComponent)baseDefn.Definition.DeepCopy(); // If the differential overrides the elementdefn, only some of the fields go into the slicing entry if (diff.Definition != null) { if (diff.Definition.CommentsElement != null) slicingEntry.Definition.CommentsElement = (FhirString)diff.Definition.CommentsElement.DeepCopy(); if (diff.Definition.ShortElement != null) slicingEntry.Definition.ShortElement = (FhirString)diff.Definition.ShortElement.DeepCopy(); if (diff.Definition.FormalElement != null) slicingEntry.Definition.FormalElement = (FhirString)diff.Definition.FormalElement.DeepCopy(); if (diff.Definition.MinElement != null) slicingEntry.Definition.MinElement = (Integer)diff.Definition.MinElement.DeepCopy(); if (diff.Definition.MaxElement != null) slicingEntry.Definition.MaxElement = (FhirString)diff.Definition.MaxElement.DeepCopy(); } return slicingEntry; }
private Profile.ElementComponent createExtensionSlicingEntry(string path) { // Create a pre-fab extension slice, filled with sensible defaults var result = new Profile.ElementComponent(); result.Path = path; result.Slicing = new Profile.ElementSlicingComponent(); result.Slicing.Discriminator = "url"; result.Slicing.Ordered = false; result.Slicing.Rules = Profile.SlicingRules.Open; return result; }