File: System\Transactions\Trace\TraceXPathNavigator.cs
Project: ndp\cdf\src\NetFx20\System.Transactions\System.Transactions.csproj (System.Transactions)
//-----------------------------------------------------------------------------
// <copyright file="PlainXmlWriter.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Very basic performance-oriented XmlWriter implementation. No validation/encoding is made.
// Namespaces are not supported
// Minimal formatting support
//-----------------------------------------------------------------------------
 
namespace System.Transactions.Diagnostics
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Text;
    using System.Xml.XPath;
    using System.Xml;
    
    class TraceXPathNavigator : XPathNavigator
    {
        ElementNode root = null;
        ElementNode current = null;
        bool closed = false;
        XPathNodeType state = XPathNodeType.Element;
 
        class ElementNode
        {
            internal ElementNode(string name, string prefix, string xmlns, ElementNode parent)
            {
                this.name = name;
                this.prefix = prefix;
                this.xmlns = xmlns;
                this.parent = parent;
            }
 
            internal string name;
            internal string xmlns;
            internal string prefix;
            internal List<ElementNode> childNodes = new List<ElementNode>();
            internal ElementNode parent;
            internal List<AttributeNode> attributes = new List<AttributeNode>();
            internal TextNode text;
            internal bool movedToText = false;
 
            internal ElementNode MoveToNext()
            {
                ElementNode retval = null;
                if ((this.elementIndex + 1) < this.childNodes.Count)
                {
                    ++this.elementIndex;
                    retval = this.childNodes[this.elementIndex];
                }
                return retval;
            }
 
            internal bool MoveToFirstAttribute()
            {
                this.attributeIndex = 0;
                return this.attributes.Count > 0;
            }
 
            internal bool MoveToNextAttribute()
            {
                bool retval = false;
                if ((this.attributeIndex + 1) < this.attributes.Count)
                {
                    ++this.attributeIndex;
                    retval = true;
                }
                return retval;
            }
 
            internal void Reset()
            {
                this.attributeIndex = 0;
                this.elementIndex = 0;
                foreach (ElementNode node in this.childNodes)
                {
                    node.Reset();
                }
            }
 
            internal AttributeNode CurrentAttribute
            {
                get
                {
                    return this.attributes[this.attributeIndex];
                }
            }
 
            int attributeIndex = 0;
            int elementIndex = 0;
        }
 
        class AttributeNode
        {
            internal AttributeNode(string name, string prefix, string xmlns, string value)
            {
                this.name = name;
                this.prefix = prefix;
                this.xmlns = xmlns;
                this.nodeValue = value;
            }
 
            internal string name;
            internal string xmlns;
            internal string prefix;
            internal string nodeValue;
        }
 
        class TextNode
        {
            internal TextNode(string value)
            {
                this.nodeValue = value;
            }
            internal string nodeValue;
        }
 
        internal void AddElement(string prefix, string name, string xmlns)
        {
            ElementNode node = new ElementNode(name, prefix, xmlns, this.current);
            if (this.closed)
            {
                throw new InvalidOperationException(SR.GetString(SR.CannotAddToClosedDocument));
            }
            else
            {
                if (this.current == null)
                {
                    this.root = node;
                    this.current = this.root;
                }
                else if (!this.closed)
                {
                    this.current.childNodes.Add(node);
                    this.current = node;
                }
            }
        }
 
        internal void AddText(string value)
        {
            if (this.closed)
            {
                throw new InvalidOperationException(SR.GetString(SR.CannotAddToClosedDocument));
            }
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            else if (this.current.text != null)
            {
                throw new InvalidOperationException(SR.GetString(SR.TextNodeAlreadyPopulated));
            }
            else
            {
                this.current.text = new TextNode(value);
            }
        }
 
        internal void AddAttribute(string name, string value, string xmlns, string prefix)
        {
            if (this.closed)
            {
                throw new InvalidOperationException(SR.GetString(SR.CannotAddToClosedDocument));
            }
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            AttributeNode node = new AttributeNode(name, prefix, xmlns, value);
            this.current.attributes.Add(node);
        }
 
        internal void CloseElement()
        {
            if (this.closed)
            {
                throw new InvalidOperationException(SR.GetString(SR.DocumentAlreadyClosed));
            }
            else
            {
                this.current = this.current.parent;
                if (this.current == null)
                {
                    this.closed = true;
                }
            }
        }
 
        public override string BaseURI
        {
            get { return null; }
        }
 
        public override XPathNavigator Clone()
        {
            return this;
        }
 
        public override bool IsEmptyElement
        {
            get 
            {
                bool retval = true;
                if (this.current != null)
                {
                    retval = this.current.text != null || this.current.childNodes.Count > 0;
                }
                return retval;
            }
        }
 
        public override bool IsSamePosition(XPathNavigator other)
        {
            throw new NotSupportedException();
        }
 
        public override string LocalName
        {
            get { return this.Name; }
        }
 
        public override bool MoveTo(XPathNavigator other)
        {
            throw new NotSupportedException();
        }
 
        public override bool MoveToFirstAttribute()
        {
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            bool retval = this.current.MoveToFirstAttribute();
            if (retval)
            {
                this.state = XPathNodeType.Attribute;
            }
            return retval;
        }
 
        public override bool MoveToFirstChild()
        {
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            bool retval = false;
            if (this.current.childNodes.Count > 0)
            {
                this.current = this.current.childNodes[0];
                this.state = XPathNodeType.Element;
                retval = true;
            }
            else if (this.current.childNodes.Count == 0 && this.current.text != null)
            {
                this.state = XPathNodeType.Text;
                this.current.movedToText = true;
                retval = true;
            }
            return retval;
        }
 
        public override bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope)
        {
            return false;
        }
 
        public override bool MoveToId(string id)
        {
            throw new NotSupportedException();
        }
 
        public override bool MoveToNext()
        {
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            bool retval = false;
            if (this.state != XPathNodeType.Text)
            {
                ElementNode parent = this.current.parent;
                if (parent != null)
                {
                    ElementNode temp = parent.MoveToNext();
                    if (temp == null && parent.text != null && !parent.movedToText)
                    {
                        this.state = XPathNodeType.Text;
                        parent.movedToText = true;
                        retval = true;
                    }
                    else if (temp != null)
                    {
                        this.state = XPathNodeType.Element;
                        retval = true;
                        this.current = temp;
                    }
                }
            }
            return retval;
        }
 
        public override bool MoveToNextAttribute()
        {
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            bool retval = this.current.MoveToNextAttribute();
            if (retval)
            {
                this.state = XPathNodeType.Attribute;
            }
            return retval;
        }
 
        public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope)
        {
            return false;
        }
 
        public override bool MoveToParent()
        {
            if (this.current == null)
            {
                throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
            }
            bool retval = false;
            switch (this.state)
            {
                case XPathNodeType.Element:
                    if (this.current.parent != null)
                    {
                        this.current = this.current.parent;
                        this.state = XPathNodeType.Element;
                        retval = true;
                    }
                    break;
                case XPathNodeType.Attribute:
                    this.state = XPathNodeType.Element;
                    retval = true;
                    break;
                case XPathNodeType.Text:
                    this.state = XPathNodeType.Element;
                    retval = true;
                    break;
                case XPathNodeType.Namespace:
                    this.state = XPathNodeType.Element;
                    retval = true;
                    break;
            }
            return retval;
        }
 
        public override bool MoveToPrevious()
        {
            throw new NotSupportedException();
        }
 
        public override void MoveToRoot()
        {
            this.current = this.root;
            this.state = XPathNodeType.Element;
            this.root.Reset();
        }
 
        public override string Name
        {
            get 
            {
                if (this.current == null)
                {
                    throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
                }
                string retval = null;
                switch (this.state)
                {
                    case XPathNodeType.Element:
                        retval = this.current.name;
                        break;
                    case XPathNodeType.Attribute:
                        retval = this.current.CurrentAttribute.name;
                        break;
                }
                return retval; 
            }
        }
 
        public override System.Xml.XmlNameTable NameTable
        {
            get { return null; }
        }
 
        public override string NamespaceURI
        {
            get { return null; }
        }
 
        public override XPathNodeType NodeType
        {
            get { return this.state; }
        }
 
        public override string Prefix
        {
            get
            {
                if (this.current == null)
                {
                    throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
                }
                string retval = null;
                switch (this.state)
                {
                    case XPathNodeType.Element:
                        retval = this.current.prefix;
                        break;
                    case XPathNodeType.Attribute:
                        retval = this.current.CurrentAttribute.prefix;
                        break;
                    case XPathNodeType.Namespace:
                        retval = this.current.prefix;
                        break;
                }
                return retval;
            }
        }
 
        public override string Value
        {
            get
            {
                if (this.current == null)
                {
                    throw new InvalidOperationException(SR.GetString(SR.OperationInvalidOnAnEmptyDocument));
                }
                string retval = null;
                switch (this.state)
                {
                    case XPathNodeType.Text:
                        retval = this.current.text.nodeValue;
                        break;
                    case XPathNodeType.Attribute:
                        retval = this.current.CurrentAttribute.nodeValue;
                        break;
                    case XPathNodeType.Namespace:
                        retval = this.current.xmlns;
                        break;
                }
                return retval;
            }
        }
 
 
        public override string ToString()
        {
            this.MoveToRoot();
            StringBuilder sb = new StringBuilder();
            XmlTextWriter writer = new XmlTextWriter(new StringWriter(sb, CultureInfo.CurrentCulture));
            writer.WriteNode(this, false);
            return sb.ToString();
        }
    }
}