void InsertAndUpdateChildrenFrom(IList <AXmlObject> srcList) { for (int i = 0; i < srcList.Count; i++) { // End of our list? if (i == this.Children.Count) { InsertChild(i, srcList[i]); continue; } AXmlObject child = this.Children[i]; AXmlObject srcChild = srcList[i]; if (child.CanUpdateDataFrom(srcChild)) // includes offset test // Does it need updating? { if (child.LastUpdatedFrom != srcChild) { child.UpdateDataFrom(srcChild); AXmlContainer childAsContainer = child as AXmlContainer; if (childAsContainer != null) { childAsContainer.InsertAndUpdateChildrenFrom(((AXmlContainer)srcChild).Children); } } } else { InsertChild(i, srcChild); } } Assert(this.Children.Count == srcList.Count, "List lengths differ after update"); }
void RemoveChildrenNotIn(IList <AXmlObject> srcList) { Dictionary <int, AXmlObject> srcChildren = srcList.ToDictionary(i => i.StartOffset); for (int i = 0; i < this.Children.Count;) { AXmlObject child = this.Children[i]; AXmlObject srcChild; if (srcChildren.TryGetValue(child.StartOffset, out srcChild) && child.CanUpdateDataFrom(srcChild)) { // Keep only one item with given offset (we might have several due to deletion) srcChildren.Remove(child.StartOffset); // If contaner that needs updating AXmlContainer childAsContainer = child as AXmlContainer; if (childAsContainer != null && child.LastUpdatedFrom != srcChild) { childAsContainer.RemoveChildrenNotIn(((AXmlContainer)srcChild).Children); } i++; } else { RemoveChild(i); } } }
/// <remarks> /// Note the the method is not called recuively. /// Only the helper methods are recursive. /// </remarks> internal void UpdateTreeFrom(AXmlContainer srcContainer) { this.StartOffset = srcContainer.StartOffset; // Force the update this.UpdateDataFrom(srcContainer); RemoveChildrenNotIn(srcContainer.Children); InsertAndUpdateChildrenFrom(srcContainer.Children); }
/// <inheritdoc/> public override IEnumerable <AXmlObject> GetSelfAndAllChildren() { return((new AXmlObject[] { this }).Flatten( delegate(AXmlObject i) { AXmlContainer container = i as AXmlContainer; if (container != null) { return container.Children; } else { return null; } } )); }
/// <summary> Recursively fix all parent pointer in a tree </summary> /// <remarks> /// Cache constraint: /// If cached item has parent set, then the whole subtree must be consistent and document set /// </remarks> void SetParentPointersInTree(AXmlObject item) { // All items come from the parser cache if (item.Parent == null) { // Dangling object - either a new parser object or removed tree (still cached) item.Parent = this; item.Document = this.Document; AXmlContainer container = item as AXmlContainer; if (container != null) { foreach (AXmlObject child in container.Children) { container.SetParentPointersInTree(child); } } } else if (item.Parent == this) { // If node is attached and then deattached, it will have null parent pointer // but valid subtree - so its children will alredy have correct parent pointer // like in this case // item.DebugCheckConsistency(false); // Rest of the tree is consistent - do not recurse } else { // From cache & parent set => consitent subtree // item.DebugCheckConsistency(false); // The parent (or any futher parents) can not be part of parsed document // becuase otherwise this item would be included twice => safe to change parents // Maintain cache constraint by setting parents to null foreach (AXmlObject ancest in item.GetAncestors().ToList()) { ancest.Parent = null; } item.Parent = this; // Rest of the tree is consistent - do not recurse } }
/// <summary> Removes object with all of its non-cached children </summary> public void RemoveParsedObject(AXmlObject obj) { // Cached objects may be used in the future - do not remove them if (obj.IsCached) { return; } segments.Remove(obj); RemoveSyntaxErrorsOf(obj); AXmlParser.Log("Stopped tracking {0}", obj); AXmlContainer container = obj as AXmlContainer; if (container != null) { foreach (AXmlObject child in container.Children) { RemoveParsedObject(child); } } }
/// <summary> /// Gets a child fully containg the given offset. /// Goes recursively down the tree. /// Specail case if at the end of attribute or text /// </summary> public AXmlObject GetChildAtOffset(int offset) { foreach (AXmlObject child in this.Children) { if ((child is AXmlAttribute || child is AXmlText) && offset == child.EndOffset) { return(child); } if (child.StartOffset < offset && offset < child.EndOffset) { AXmlContainer container = child as AXmlContainer; if (container != null) { return(container.GetChildAtOffset(offset)); } else { return(child); } } } return(this); // No childs at offset }