internal ObjectXPathNavigator(object obj, ObjectXPathContext context) { _context = context; _root = new Node(_context, new RootNodePolicy(obj)); _node = _root; if (_context.DetectLoops) { _navigationStack = new Stack(); _navigationStack.Push( _root ); // Push dummy root object //_navigationStack.Push(_node.Object); //Trace( String.Format( "Ctor1: Pushedg {0} {1}", _node.Object, StackList ) ); } _lang = _context.NameTable.Add(""); }
/* protected int Depth { get { if (_parent == null) return 0; else return _parent.Depth + 1; } } protected bool ContainedBelow( Node node ) { if (node.Object == this.Object || Depth > 7 ) return true; if (_parent == null) return false; return _parent.ContainedBelow( node ); }*/ /// <summary> /// Adds the child to this node. /// </summary> /// <param name="child">Child node to add.</param> /// <remarks>This method should be used with caution, because it could /// cause interference with child nodes returned by the node policy.</remarks> public void AddChild( Node child ) { int index = ChildrenCount; CacheChild( index, child ); child.Parent = this; child.Index = index; _elementsCount = ChildrenCount + 1; }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToRoot" /> for details. /// </summary> public override void MoveToRoot() { #if DEBUG Trace("MoveToRoot"); #endif _node = _root; _childNav = null; if (_context.DetectLoops) { _navigationStack.Clear(); Trace( () => String.Format("Move2Root {0} {1}", _node.Object, GetNavigationStack())); //_navigationStack.Push(_root.Object); } }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToParent" /> for details. /// </summary> public override bool MoveToParent() { #if DEBUG Trace("MoveToParent"); Trace( GetNavigationStack ); //System.Diagnostics.StackTrace st = new StackTrace(); //Trace( st.ToString() ); #endif // Invoke child navigator if (_childNav != null) { Trace(() => String.Format("Trace: ChildNav")); if (_childNavDepth == 0) { // We reached root node of the child navigator _childNav = null; if (!_node.IsTransparent) // Child navigator cleared, we are at its non-transparent container return true; } else { // Descend one level _childNav.MoveToParent(); _childNavDepth--; return true; } } Node parent = GetNonTransparentParent(_node); if (_context.DetectLoops) if (parent != null) { Trace( () => String.Format("Move2Parent popping {0}", GetNavigationStack())); if (_navigationStack.Count > 0) _navigationStack.Pop(); else { Trace(() => String.Format( "MoveToParent: Stack is empty") ); } } if (parent != null) { _node = parent; return true; } return false; }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToNextAttribute" /> for details. /// </summary> public override bool MoveToNextAttribute() { #if DEBUG Trace("MoveToNextAttribute"); #endif // Invoke child navigator if (_childNav != null) return _childNav.MoveToNextAttribute(); if (_node.NodeType != XPathNodeType.Attribute) return false; for (int i = _node.Index + 1; i < _node.Parent.AttributesCount; i++) { Node newnode = _node.Parent.GetAttribute(i); if (newnode != null && !newnode.IsTransparent) { _node = newnode; if (_context.DetectLoops) { Trace( () => String.Format("Move2NextAttr popping {0}", GetNavigationStack())); if (_navigationStack.Count > 0) _navigationStack.Pop(); else Trace(() => String.Format("MoveToNextAttribute: Stack is empty {0}", GetNavigationStack())); _navigationStack.Push(newnode.Object); //Trace(String.Format("~Move2NextAttr Pushed {0} {1}", _node.Object, StackList)); } return true; } } Trace(() => String.Format("~Move2NextAttr")); return false; }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToPrevious" /> for details. /// </summary> public override bool MoveToPrevious() { #if DEBUG Trace("MoveToPrevious"); #endif // Invoke child navigator if (_childNav != null) { bool res = _childNav.MoveToPrevious(); if (res) return true; if (!_node.IsTransparent || _childNavDepth > 0) return false; } Node newnode = GetNonTransparentSibling(_node, false); while (newnode != null) { if (!newnode.IsTransparent) { _node = newnode; _childNav = null; if (_context.DetectLoops) { Trace( () => String.Format("Move2Prev Pushing {0} {1}", _node.Object, GetNavigationStack())); if (_navigationStack.Count > 0) _navigationStack.Pop(); else { Trace( () => String.Format("{0} MoveToPrevious : stack empty", Object)); } _navigationStack.Push(newnode.Object); } return true; } else { // It's transparent but navigable node. // Try to move into this navigable node. if (MoveIntoNavigableNode(newnode)) { _node = newnode; // Go to the last sibling of the child navigator's node while (_childNav.MoveToNext()) ; if (_context.DetectLoops) { Trace( () => String.Format("Move2Prev {0} {1}", _node.Object, GetNavigationStack())); if (_navigationStack.Count > 0) _navigationStack.Pop(); else { Trace( () => String.Format("{0} MoveToPrevious : stack is empty", Object)); } _navigationStack.Push(newnode.Object); } return true; } // If failure, get its sibling newnode = GetNonTransparentSibling(newnode, false); continue; } } return false; }
private static Node GetNonTransparentParent(Node node) { Node parent = node.Parent; while (parent != null && parent.IsTransparent) { parent = parent.Parent; } return parent; }
/// <summary> /// Caches attribute. /// </summary> /// <param name="i">Zero-based index of attribute.</param> /// <param name="child">Attribute to add..</param> private void CacheAttribute( int i, Node child ) { CheckCache( 0 ); _cache[i] = ( child != null ? child : NullCacheEntry ); }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToFirstAttribute" /> for details. /// </summary> public override bool MoveToFirstAttribute() { #if DEBUG Trace("MoveToFirstAttribute"); #endif // Invoke child navigator if (_childNav != null) { bool res = _childNav.MoveToFirstAttribute(); if (res) _childNavDepth++; return res; } if (_node.AttributesCount == 0) return false; for (int i = 0; i < _node.AttributesCount; i++) { Node newnode = _node.GetAttribute(i); if (newnode != null && !newnode.IsTransparent) { _node = newnode; if (_context.DetectLoops) { _navigationStack.Push(_node.Object); Trace( () => String.Format("Move2.1stAttr Pushed {0} {1}", _node.Object, GetNavigationStack())); } return true; } } return false; }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToAttribute" /> for details. /// </summary> public override bool MoveToAttribute(string localName, string namespaceURI) { #if DEBUG Trace("MoveToAttribute"); #endif // Invoke child navigator if (_childNav != null) { bool res = _childNav.MoveToAttribute(localName, namespaceURI); if (res) _childNavDepth++; return res; // TODO: Check what will happen if we are positioned at the navigable root of the transparent node. } if (_node.NodeType != XPathNodeType.Element) return false; int i = _node.FindAttribute(localName, namespaceURI); if (i >= 0) { Node newnode = _node.GetAttribute(i); if (newnode != null && !newnode.IsTransparent) { _node = newnode; return true; } } return false; }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveTo" /> for details. /// </summary> public override bool MoveTo(XPathNavigator other) { var otherNav = other as ObjectXPathNavigator; if( otherNav == null ) { return false; } _context = otherNav._context; _root = otherNav._root; _node = otherNav._node; if( otherNav._childNav != null ) { _childNav = otherNav._childNav.Clone(); _childNavDepth = otherNav._childNavDepth; } else _childNav = null; #if DEBUG Trace( () => string.Format( "MoveTo( N#{0} )", other.GetHashCode() ) ); #endif if( _context.DetectLoops ) { _navigationStack = (Stack) otherNav._navigationStack.Clone(); } return true; }
private Node GetNonTransparentSibling(Node current, bool goForward) { if( current.NodeType == XPathNodeType.Attribute ) return null; Node newnode = null; Node parent = current.Parent; if( parent == null ) return null; Object old = null; if( _context.DetectLoops ) if( _navigationStack.Count > 0 ) old = _navigationStack.Pop(); do { newnode = goForward ? parent.GetChild( current.Index + 1 ) : parent.GetChild( current.Index - 1 ); // While there are no more nodes in this transparent parent, try to // ascend up the hierarchy and take node next to this transparent node. while( newnode == null && parent.IsTransparent ) { newnode = parent; parent = parent.Parent; newnode = goForward ? parent.GetChild( newnode.Index + 1 ) : parent.GetChild( newnode.Index - 1 ); } // If node is found but it is transparent and not navigable if( newnode != null && newnode.IsTransparent && !IsNodeXPathNavigable( newnode ) ) { current = newnode; newnode = GetNonTransparentChild( current, goForward ); if( newnode != null ) break; else continue; } // If we have to detect loops else if( _context.DetectLoops ) if( newnode != null && newnode.Object != null && _navigationStack.Contains( newnode.Object ) ) { var evt = new LoopDetectionEventArgs( this, newnode ); _context.OnLoopDetected( evt ); if( !evt.IgnoreLoop ) { current = newnode; continue; } } break; } while( true ); if( old != null ) _navigationStack.Push( old ); return newnode; }
private Node GetNonTransparentChild(Node current, bool goForward) { if( current.ChildrenCount == 0 ) return null; Node newNode; bool inStack = false; int index = goForward ? 0 : current.ChildrenCount - 1; do { newNode = current.GetChild( index ); if( newNode == null && current.IsTransparent ) return GetNonTransparentSibling( current, goForward ); // If we have to detect loops. if( _context.DetectLoops ) { if( newNode != null && newNode.Object != null && _navigationStack.Contains( newNode.Object ) ) { var evt = new LoopDetectionEventArgs( this, newNode ); _context.OnLoopDetected( evt ); if( !evt.IgnoreLoop ) { inStack = true; Trace( () => String.Format( "GetNonTransparentChild {0} already in stack", newNode.Object ) ); if( goForward ) index++; else index--; continue; } } else inStack = false; } current = newNode; if( current != null ) index = goForward ? 0 : current.ChildrenCount - 1; } while( inStack || ( current != null && current.IsTransparent && !IsNodeXPathNavigable( current ) ) ); // Break if current is null, or non trasparent or navigable return current; }
private void CheckCache( int elemIndex ) { int elCount = ChildrenCount; if( _cache == null ) { int size = AttributesCount; if( elCount == int.MaxValue || elCount <= elemIndex ) { if( elemIndex >= MinimalElementsCacheSize ) size += elemIndex + 1; else // Initial elements cache size for unknown number of children size += MinimalElementsCacheSize; } else size += elCount; if( size != 0 ) _cache = new Node[ size ]; else _cache = EmptyCache; } else if( elCount == int.MaxValue || elCount <= elemIndex ) { // Check if cache has to be expanded int size = _cache.Length; int elemSize = size - AttributesCount; if( elemIndex >= elemSize ) { Node[] newCache = new Node[size + elemSize]; Array.Copy( _cache, 0, newCache, 0, size ); } } }
/// <summary> /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToFirstChild" /> for details. /// </summary> public override bool MoveToFirstChild() { #if DEBUG Trace("MoveToFirstChild"); #endif // Invoke child navigator if (_childNav != null) { bool res = _childNav.MoveToFirstChild(); if (res) _childNavDepth++; return res; } // Check if we are trying to descend into IXPathNavigable object if (IsNodeXPathNavigable(_node)) { if (MoveIntoNavigableNode(_node)) return true; else return false; } Node newnode = GetNonTransparentChild(_node, true); while (newnode != null) { if (!newnode.IsTransparent) { _node = newnode; if (_context.DetectLoops) { Trace( () => String.Format("MoveTo1stChild Pushing {0} {1} TRUE", _node.Object, GetNavigationStack())); _navigationStack.Push(newnode.Object); } return true; } else { // It's transparent but navigable node. // Try to move into this navigable node. if (MoveIntoNavigableNode(newnode)) { _node = newnode; if (_context.DetectLoops) { Trace( () => String.Format("T: MoveTo1stChild Pushing {0} {1} TRUE", _node.Object, GetNavigationStack())); _navigationStack.Push(newnode.Object); } return true; } // If failure, get its sibling newnode = GetNonTransparentSibling(newnode, true); continue; } } return false; }
/// <summary> /// Caches child element. /// </summary> /// <param name="i">Zero-based index of child element.</param> /// <param name="child">Child element to add.</param> private void CacheChild( int i, Node child ) { CheckCache( i ); _cache[AttributesCount + i] = ( child != null ? child : NullCacheEntry ); }
private bool MoveIntoNavigableNode(Node node) { IXPathNavigable navigable = node.Object as IXPathNavigable; if (navigable != null) { _childNav = navigable.CreateNavigator(); _childNavDepth = 0; if (_childNav.NodeType == XPathNodeType.Root || (node.Member != null && node.Member.SkipNavigableRoot != null)) { bool res = _childNav.MoveToFirstChild(); if (!res) { // The type of node is Root and we can't descend to a child _childNav = null; return false; } _childNav.MoveToFirst(); } // Descended succesfully return true; } return false; }
/// <summary> /// Creates a new <see cref="LoopDetectionEventArgs"/> instance. /// </summary> /// <param name="navigator"><see cref="ObjectXPathNavigator"/> Navigator object</param> /// <param name="node"><see cref="Node"/> Node that caused loop appearance</param> public LoopDetectionEventArgs( ObjectXPathNavigator navigator, Node node ) { _navigator = navigator; _node = node; _ignoreLoop = false; }
private static bool IsNodeXPathNavigable(Node node) { if (node.ObjectType == null) return false; else return node.ObjectType.IsXPathNavigable; }