Click here to Skip to main content
15,880,854 members
Articles / Programming Languages / XML

Simplify Reading and Writing of XML Fragments

Rate me:
Please Sign up or sign in to vote.
3.35/5 (6 votes)
8 Aug 2006 43.5K   858   19  
This article shows how to read and write XML fragments using the XmlChunkReader and XmlChunkWriter classes.
/* Copyright (c) 2006 notmasteryet */
using System;
using System.Xml;

namespace XmlChunk
{
    /// <summary>
    /// XmlChunkReader can be created using XmlReader while it�s reading 
    /// XML element node. It can be used as standalone XmlReader, e.g. 
    /// to perform deserialization operation. When XmlChunkReader is closed, 
    /// main reader points to next XML node. Using of XmlChunkReader 
    /// helps avoid such calls as ReadInnerXml.
    /// </summary>
    public class XmlChunkReader : XmlReader
    {
        private XmlReader baseReader;
        private int depth;
        private State state;
        private bool isRootElementEmpty;

        /// <summary>
        /// Cointains base reader
        /// </summary>
        public XmlReader BaseReader
        {
            get { return baseReader; }
        }

        /// <summary>
        /// Creates reader
        /// </summary>
        /// <param name="reader">Base reader</param>
        public XmlChunkReader(XmlReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if(reader.NodeType != XmlNodeType.Element)
                throw new ArgumentException(Properties.Resources.ReaderInvalidState, "reader");

            this.baseReader = reader;
            this.depth = baseReader.Depth;
            this.state = State.Idle;
        }

        public override int AttributeCount
        {
            get { return BaseReader.AttributeCount; }
        }

        public override string BaseURI
        {
            get { return BaseReader.BaseURI; }
        }

        public override void Close()
        {
            while (state != State.Completed) Skip();
        }

        public override int Depth
        {
            get { return BaseReader.Depth - depth; }
        }

        public override bool EOF
        {
            get { return state == State.Completed; }
        }

        public override string GetAttribute(int i)
        {
            return BaseReader.GetAttribute(i);
        }

        public override string GetAttribute(string name, string namespaceURI)
        {
            return BaseReader.GetAttribute(name, namespaceURI);
        }

        public override string GetAttribute(string name)
        {
            return BaseReader.GetAttribute(name);
        }

        public override bool HasValue
        {
            get { return BaseReader.HasValue; }
        }

        public override bool IsEmptyElement
        {
            get { return BaseReader.IsEmptyElement; }
        }

        public override string LocalName
        {
            get { return BaseReader.LocalName; }
        }

        public override string LookupNamespace(string prefix)
        {
            return BaseReader.LookupNamespace(prefix);
        }

        private bool ChangeStateIfTrue(bool check, State newState)
        {
            if (check) state = newState;
            return check;
        }

        public override bool MoveToAttribute(string name, string ns)
        {
            return ChangeStateIfTrue(BaseReader.MoveToAttribute(name, ns), State.OnAttribute);
        }

        public override bool MoveToAttribute(string name)
        {
            return ChangeStateIfTrue(BaseReader.MoveToAttribute(name), State.OnAttribute);
        }

        public override bool MoveToElement()
        {
            return ChangeStateIfTrue(BaseReader.MoveToElement(), State.InProcess);
        }

        public override bool MoveToFirstAttribute()
        {
            return ChangeStateIfTrue(BaseReader.MoveToFirstAttribute(), State.OnAttribute);
        }

        public override bool MoveToNextAttribute()
        {
            return BaseReader.MoveToNextAttribute();
        }

        public override XmlNameTable NameTable
        {
            get { return BaseReader.NameTable; }
        }

        public override string NamespaceURI
        {
            get { return BaseReader.NamespaceURI; }
        }

        public override XmlNodeType NodeType
        {
            get { return BaseReader.NodeType; }
        }

        public override string Prefix
        {
            get { return BaseReader.Prefix; }
        }

        public override bool Read()
        {
            switch (state)
            {
                case State.Idle:
                    state = State.InProcess;
                    isRootElementEmpty = BaseReader.IsEmptyElement;
                    return true;
                case State.OnAttribute:
                    return BaseReader.Read();
                case State.Completed:
                    return false;
                default:
                case State.InProcess:                    
                    if (BaseReader.Depth == depth &&
                        (isRootElementEmpty || BaseReader.NodeType == XmlNodeType.EndElement))
                    {
                        // reading last node of the "root" element
                        state = State.Completed;
                        BaseReader.Read();
                        return false;
                    }
                    else
                    {
                        // normal reading
                        bool moreData = BaseReader.Read();
                        if (!moreData) state = State.Completed;
                        return moreData;
                    }
            }
        }

        public override bool ReadAttributeValue()
        {
            return BaseReader.ReadAttributeValue();
        }

        public override ReadState ReadState
        {
            get 
            {
                switch (state)
                {
                    case State.Idle:
                        return ReadState.Initial;
                    case State.Completed:
                        return ReadState.EndOfFile;
                    default:
                    case State.InProcess:
                        return BaseReader.ReadState;
                }
            }
        }

        public override void ResolveEntity()
        {
            BaseReader.ResolveEntity();
        }

        public override string Value
        {
            get { return BaseReader.Value; }
        }

        private enum State
        {
            Idle,
            InProcess,
            OnAttribute,
            Completed
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions