Click here to Skip to main content
15,884,472 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>
    /// XmlChunkWriter can be created using XmlWriter. It can be used 
    /// as standalone XmlWriter, e.g. to perform serialization of the 
    /// objects. When XmlChunkWriter is closed, main XmlWriter is ready 
    /// to continue write XML data. Using of XmlChunkWriter helps format 
    /// data is same manner and avoid writing of xml declaration 
    /// instruction in the middle of XML.
    /// </summary>
    public class XmlChunkWriter : XmlWriter
    {
        private const string XmlnsPrefix = "xmlns";
        private const string XmlnsXsiName = "xsi";
        private const string XmlnsXsdName = "xsd";

        private XmlWriter baseWriter;
        private bool skipXsiNsAttributes;
        private int depth;
        private State state;

        /// <summary>
        /// Contains base XmlWriter
        /// </summary>
        public XmlWriter BaseWriter
        {
            get 
            {
                if (state == State.Completed)
                    throw new InvalidOperationException(Properties.Resources.WriterIsClosed);
                
                return baseWriter; 
            }
        }

        /// <summary>
        /// Creates writer
        /// </summary>
        /// <param name="writer">Base writer</param>
        public XmlChunkWriter(XmlWriter writer) : this(writer, true)
        {
        }

        /// <summary>
        /// Creates writer
        /// </summary>
        /// <param name="writer">Base writer</param>
        /// <param name="skipXsiNsAttributes">Root xmlns:xsi and xmlns:xsd attributes will be removed if true</param>
        public XmlChunkWriter(XmlWriter writer, bool skipXsiNsAttributes)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            this.baseWriter = writer;
            this.skipXsiNsAttributes = skipXsiNsAttributes;
            this.depth = 0;
            this.state = State.Idle;
        }

        public override void Close()
        {
            BaseWriter.Flush();
            state = State.Completed;
        }

        public override void Flush()
        {
            BaseWriter.Flush();
        }

        public override string LookupPrefix(string ns)
        {
            return BaseWriter.LookupPrefix(ns);
        }

        public override void WriteBase64(byte[] buffer, int index, int count)
        {
            BaseWriter.WriteBase64(buffer, index, count);
        }

        public override void WriteCData(string text)
        {            
            BaseWriter.WriteCData(text);
        }

        public override void WriteCharEntity(char ch)
        {
            if (state == State.SkipAttribute) return;
            BaseWriter.WriteCharEntity(ch);
        }

        public override void WriteChars(char[] buffer, int index, int count)
        {
            if (state == State.SkipAttribute) return;
            BaseWriter.WriteChars(buffer, index, count);
        }

        public override void WriteComment(string text)
        {
            BaseWriter.WriteComment(text);
        }

        public override void WriteDocType(string name, string pubid, string sysid, string subset)
        {            
        }

        public override void WriteEndAttribute()
        {
            if (state != State.SkipAttribute)
            {
                BaseWriter.WriteEndAttribute();
            }
            else
                state = State.InProcess;
        }

        public override void WriteEndDocument()
        {            
        }

        public override void WriteEndElement()
        {
            BaseWriter.WriteEndElement();
            --depth;
        }

        public override void WriteEntityRef(string name)
        {
            if (state == State.SkipAttribute) return;
            BaseWriter.WriteEntityRef(name);
        }

        public override void WriteFullEndElement()
        {
            BaseWriter.WriteFullEndElement();
            --depth;
        }

        public override void WriteProcessingInstruction(string name, string text)
        {
            BaseWriter.WriteProcessingInstruction(name, text);
        }

        public override void WriteRaw(string data)
        {
            BaseWriter.WriteRaw(data);
        }

        public override void WriteRaw(char[] buffer, int index, int count)
        {
            BaseWriter.WriteRaw(buffer, index, count);
        }

        protected virtual bool IsXsiAttribute(string prefix, string localName, string ns)
        {
            return prefix == XmlnsPrefix && 
                (localName == XmlnsXsiName || localName == XmlnsXsdName);
        }

        public override void WriteStartAttribute(string prefix, string localName, string ns)
        {
            if (depth == 1 && skipXsiNsAttributes && IsXsiAttribute(prefix ,localName, ns))
            {
                // skiping attribute with namespace definition in root node
                state = State.SkipAttribute;
                return;
            }

            BaseWriter.WriteStartAttribute(prefix, localName, ns);
        }

        public override void WriteStartDocument(bool standalone)
        {
        }

        public override void WriteStartDocument()
        {
        }

        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            BaseWriter.WriteStartElement(prefix, localName, ns);
            state = State.InProcess;
            ++depth;
        }

        public override WriteState WriteState
        {
            get 
            { 
                switch(state)
                {
                    case State.Idle:
                        return WriteState.Start;
                    default:
                    case State.InProcess:
                        return BaseWriter.WriteState;
                    case State.SkipAttribute:
                        return WriteState.Attribute;
                    case State.Completed:
                        return WriteState.Closed;
                }
            }
        }

        public override void WriteString(string text)
        {
            if (state == State.SkipAttribute) return;
            BaseWriter.WriteString(text);
        }

        public override void WriteSurrogateCharEntity(char lowChar, char highChar)
        {
            if (state == State.SkipAttribute) return;
            BaseWriter.WriteSurrogateCharEntity(lowChar, highChar);
        }

        public override void WriteWhitespace(string ws)
        {
            BaseWriter.WriteWhitespace(ws);
        }

        private enum State
        {
            Idle,
            InProcess,
            SkipAttribute,
            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