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
            }

            _lang = _context.NameTable.Add( "" );
        }
        /// <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;
            }

            var 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;
                }
                // 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;
        }
        /// <summary>
        /// See <see cref="System.Xml.XPath.XPathNavigator.MoveToParent" /> for details.
        /// </summary>
        public override bool MoveToParent()
        {
            #if DEBUG
            Trace( "MoveToParent" );
            Trace( GetNavigationStack );
            #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;
                }
            }

            var 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++ )
            {
                var 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 );
                    }
                    return true;
                }
            }
            Trace( () => string.Format( "~Move2NextAttr" ) );
            return false;
        }
        /// <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 ) )
                return MoveIntoNavigableNode( _node );

            var 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;
                }
                // 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>
        /// 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++ )
            {
                var 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;
        }
Exemplo n.º 7
0
 /// <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;
 }
 private static bool IsNodeXPathNavigable( Node node )
 {
     if( node.ObjectType == null )
         return false;
     return node.ObjectType.IsXPathNavigable;
 }
        private Node GetNonTransparentSibling( Node current, bool goForward )
        {
            if( current.NodeType == XPathNodeType.Attribute )
                return null;

            Node newnode;
            var 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;
                    continue;
                }

                // 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 )
                        {
                            current = newnode;
                            continue;
                        }
                    }
                break;
            } while( true );

            if( old != null )
                _navigationStack.Push( old );

            return newnode;
        }
        private bool MoveIntoNavigableNode( Node node )
        {
            var 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;
        }
Exemplo n.º 11
0
        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;

                _cache = size != 0 ? new Node[size] : 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 )
                {
                    var newCache = new Node[size + elemSize];
                    Array.Copy( _cache, 0, newCache, 0, size );
                }
            }
        }
Exemplo n.º 12
0
 /// <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 ?? NullCacheEntry );
 }
Exemplo n.º 13
0
 /// <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 ?? NullCacheEntry );
 }
        /// <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() ) );
            }
        }
        /// <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 static Node GetNonTransparentParent( Node node )
 {
     var parent = node.Parent;
     while( parent != null && parent.IsTransparent )
         parent = parent.Parent;
     return parent;
 }
        /// <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 )
            {
                var newnode = _node.GetAttribute( i );
                if( newnode != null && !newnode.IsTransparent )
                {
                    _node = newnode;
                    return true;
                }
            }
            return false;
        }
        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;
        }
 /// <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;
 }