XmlCompatibilityReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Base / System / Windows / Markup / XmlCompatibilityReader.cs / 1 / XmlCompatibilityReader.cs

                            /****************************************************************************\ 
*
* File: XmlCompatibilityReaderr.cs
*
* Purpose: 
*
* History: 
*    5/11/05:    [....]        Created 
*    9/16/05:    [....]      Modified
*    9/16/05:    [....]      Modified 
*
* Copyright (C) 2005 by Microsoft Corporation.  All rights reserved.
*
\***************************************************************************/ 

using System; 
using System.Xml; 
using System.Collections.Generic;
using System.Globalization; 
using System.Diagnostics;

#if PBTCOMPILER
using MS.Utility; 
namespace MS.Internal.Markup
#else 
using MS.Internal.WindowsBase; 
using System.Windows;
 
namespace System.Windows.Markup
#endif
{
#if !PBTCOMPILER 
    [FriendAccessAllowed]
#endif 
 
    // 
    // true if xmlNamespace is recognized 
    // 
    // 
    // the namespace to be checked
    //  
    // 
    // if the passed in namespace is subsumed, then newXmlNamespace returns the subsuming namespace. 
    //  
    internal delegate bool IsXmlNamespaceSupportedCallback(string xmlNamespace, out string newXmlNamespace);
    delegate void HandleElementCallback(int elementDepth, ref bool more); 
    delegate void HandleAttributeCallback(int elementDepth);
#if !PBTCOMPILER
    [FriendAccessAllowed]
#endif 
    internal sealed class XmlCompatibilityReader: XmlWrappingReader
    { 
        #region Construction 
        public XmlCompatibilityReader(XmlReader baseReader):base(baseReader)
        { 
            _compatibilityScope = new CompatibilityScope(null, -1, this);

            foreach (string xmlNamespace in _predefinedNamespaces)
            { 
                AddKnownNamespace(xmlNamespace);
                _namespaceMap[xmlNamespace] = xmlNamespace; 
                Reader.NameTable.Add(xmlNamespace); 
            }
 
            _elementHandler.Add(AlternateContent, new HandleElementCallback(HandleAlternateContent));
            _elementHandler.Add(Choice, new HandleElementCallback(HandleChoice));
            _elementHandler.Add(Fallback, new HandleElementCallback(HandleFallback));
 
            _attributeHandler.Add(Ignorable, new HandleAttributeCallback(HandleIgnorable));
            _attributeHandler.Add(MustUnderstand, new HandleAttributeCallback(HandleMustUnderstand)); 
            _attributeHandler.Add(ProcessContent, new HandleAttributeCallback(HandleProcessContent)); 
            _attributeHandler.Add(PreserveElements, new HandleAttributeCallback(HandlePreserveElements));
            _attributeHandler.Add(PreserveAttributes, new HandleAttributeCallback(HandlePreserveAttributes)); 
        }

        public XmlCompatibilityReader(XmlReader baseReader,
            IsXmlNamespaceSupportedCallback isXmlNamespaceSupported): this(baseReader) 
        {
            _namespaceCallback = isXmlNamespaceSupported; 
        } 

        public XmlCompatibilityReader(XmlReader baseReader, 
            IsXmlNamespaceSupportedCallback isXmlNamespaceSupported,
            IEnumerable supportedNamespaces):this(baseReader, isXmlNamespaceSupported)
        {
            foreach (string xmlNamespace in supportedNamespaces) 
            {
                AddKnownNamespace(xmlNamespace); 
                _namespaceMap[xmlNamespace] = xmlNamespace; 
            }
        } 

#if !PBTCOMPILER
        public XmlCompatibilityReader(XmlReader baseReader,
            IEnumerable supportedNamespaces):this(baseReader, null, supportedNamespaces) 
        {
        } 
#endif 
        #endregion Construction
 
        #region Public Methods
        /// 
        /// replaces all future references of namespace URI 'oldNamespace' with 'newNamespace'
        ///  
        /// 
        /// the namespace to subsume with 
        ///  
        /// 
        /// the namespace to be subsumed 
        /// 
        public void DeclareNamespaceCompatibility(string newNamespace, string oldNamespace)
        {
            if(newNamespace != oldNamespace) 
            {
                // indicate that newNamespace subsumes another namespace 
                AddSubsumingNamespace(newNamespace); 

                // If newNamespace is mapped to a namespace, 
                string tempNamespace;
                if (_namespaceMap.TryGetValue(newNamespace, out tempNamespace))
                {
                    // If we have mapped newNamespace already get the newest name. 
                    // We don't have to do this recursively because of the code below
                    // ensures the map always refers to the newest namespace. 
                    newNamespace = tempNamespace; 
                }
 
                if(IsSubsumingNamespace(oldNamespace))
                {
                    // if we are mapping what was used as a new namespace to a newer name,
                    // scan the _newNamespaces dictionary and update the entries. We collect 
                    // a list to avoid updating the dictonary during enumeration.
                    List keysToUpdate = new List(); 
 
                    foreach (KeyValuePair pair in _namespaceMap)
                    { 
                        if (pair.Value == oldNamespace)
                        {
                            keysToUpdate.Add(pair.Key);
                        } 
                    }
 
                    foreach (string key in keysToUpdate) 
                    {
                        _namespaceMap[key] = newNamespace; 
                    }
                }
            }
 
            _namespaceMap[oldNamespace] = newNamespace;
        } 
 
        /// 
        /// Reads the next node from the stream. 
        /// 
        /// 
        /// true if the next node was read successfully; false if there are no more nodes to read.
        ///  
        public override bool Read()
        { 
            bool more = Reader.Read(); //passed as ref arg to ReadStartElement and ReadEndElement 
            bool result = false;
 
            while (more)
            {
                switch (Reader.NodeType)
                { 
                    case XmlNodeType.Element:
                    { 
                        // if the element read should be ignored, read the next element 
                        if(!ReadStartElement(ref more))
                        { 
                            continue;
                        }
                        break;
                    } 
                    case XmlNodeType.EndElement:
                    { 
                        // if the element read should be ignored, read the next element 
                        if(!ReadEndElement(ref more))
                        { 
                            continue;
                        }
                        break;
                    } 
                }
 
                // if the element was read successfully and was not ignored, break and return true 
                result = true;
                break; 
            }

            return result;
        } 

        ///  
        /// Used to handle 'start element' tags.  These are actually 
        /// just called 'element' tags, the 'start' is just for clarity
        ///  
        /// 
        /// is set to true if there is the document contains more elements, false if the end of the
        /// document has been reached.
        ///  
        /// 
        /// true if an element was read that should not be ignored 
        /// false if the element read should be ignored or the end of document has been reached 
        /// 
        private bool ReadStartElement(ref bool more) 
        {
            // when processing elements, the Reader may advance to another element or attribute,
            // so we save the values of the current element here
            int elementDepth = Reader.Depth; 
            int depthOffset = _depthOffset;
            bool isEmpty = Reader.IsEmptyElement; 
            string namespaceName = NamespaceURI; 
            bool result = false;
 
            if (object.ReferenceEquals(namespaceName, CompatibilityUri))
            {
                // if the element is a markup-compatibility element, we get the appropriate handler for
                // the element type, and call the appropriate delegate.  If the element is not recognized 
                // we throw an exception.
                string elementName = Reader.LocalName; 
                HandleElementCallback elementCB; 
                if(!_elementHandler.TryGetValue(elementName, out elementCB))
                { 
                    Error(SR.Get(SRID.XCRUnknownCompatElement), elementName);
                }
                elementCB(elementDepth, ref more);
            } 
            // handle non-markup-compatibility elements
            else 
            { 
                // check for markup-compatibility attributes and namespaces that should be ignored
                ScanForCompatibility(elementDepth); 

                if (ShouldIgnoreNamespace(namespaceName))
                {
                    if(Scope.ShouldProcessContent(namespaceName, Reader.LocalName)) 
                    {
                        // if the current element is unknown and has been marked Ignorable and ProcessContent, 
                        // then read the next element, and increase depth offset 
                        if(Scope.Depth == elementDepth)
                        { 
                            // if the current element pushed a scope, mark the scope as InProcessContent to
                            // note that for certain logic this scope's parent should be checked
                            Scope.InProcessContent = true;
                        } 
                        _depthOffset++;
                        more = Reader.Read(); 
                    } 
                    else
                    { 
                        // if element should be ignored but not processed, check to see if scope must be popped,
                        // then skip to the next element after the end tag of the current element
                        ScanForEndCompatibility(elementDepth);
                        Reader.Skip(); 
                    }
                } 
                else 
                {
                    if (Scope.InAlternateContent) 
                    {
                        // if this element is the child of an AlternateContent element, then throw an exception.
                        Error(SR.Get(SRID.XCRInvalidACChild), Reader.Name);
                    } 

                    result = true; 
                } 
            }
 
            // if the element is empty (e.g. "" and we pushed a scope then get
            // rid of the scope
            if(isEmpty)
            { 
                ScanForEndCompatibility(elementDepth);
                _depthOffset = depthOffset; 
            } 

            return result; 
        }


        ///  
        /// Used to handle any end element tag
        ///  
        ///  
        /// is set to true if there is the document contains more elements, false if the end of the
        /// document has been reached. 
        /// 
        /// 
        /// true if an element was read that should not be ignored
        /// false if the element read should be ignored or the end of document has been reached 
        /// 
        private bool ReadEndElement(ref bool more) 
        { 
            // when reading attributes, the reader's depth increases, so for consistency
            // we store the depth before reading any attributes 
            int elementDepth = Reader.Depth;
            string namespaceName = NamespaceURI;
            bool result = false;  // return value
 
            if (object.ReferenceEquals(namespaceName, CompatibilityUri))
            { 
                // if the element is a markup-compatibility element, pop a scope, decrement the 
                // depth offset and read the next element.
                string elementName = Reader.LocalName; 
                if (object.ReferenceEquals(elementName, AlternateContent))
                {
                    if (!Scope.ChoiceSeen)
                    { 
                        // if the current element was a , without any Choice
                        // element children, throw an exception 
                        Error(SR.Get(SRID.XCRChoiceNotFound)); 
                    }
                } 
                _depthOffset--;
                PopScope();  //we know we can pop, so no need to scan
                more = Reader.Read();
            } 
            else
            { 
                if (ShouldIgnoreNamespace(namespaceName)) 
                {
                    // if current element is Ignorable, then to be on it, it must have been marked 
                    // ProcessContent.  Pop a scope if the corresponding start element pushed a scope a
                    // scope, decrement the depth offset and read the next element.
                    Debug.Assert(Scope.ShouldProcessContent(namespaceName, Reader.LocalName));
                    ScanForEndCompatibility(elementDepth); 
                    _depthOffset--;
                    more = Reader.Read(); 
                } 
                else
                { 
                    ScanForEndCompatibility(elementDepth);
                    result = true;
                }
            } 

            return result; 
        } 

        ///  
        /// Gets the value of the attribute with the specified index.
        /// 
        /// 
        /// The index of the attribute. The index is zero-based. (The first attribute has index 0.) 
        /// 
        ///  
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned. 
        /// 
        public override string GetAttribute(int i) 
        {
            string result = null;

            if (_ignoredAttributeCount == 0) 
            {
                // if the current element should not ignored any of its attributes, skip extra logic 
                result = Reader.GetAttribute(i); 
            }
            else 
            {
                SaveReaderPosition();

                // move to 'i'th attribute, get its value 
                MoveToAttribute(i);
                result = Reader.Value; 
 
                RestoreReaderPosition();
            } 

            return result;
        }
 
        /// 
        /// Gets the value of the attribute with the specified name. 
        ///  
        /// 
        /// The qualified name of the attribute. 
        /// 
        /// 
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned.
        ///  
        public override string GetAttribute(string name)
        { 
            string result = null; 

            if (_ignoredAttributeCount == 0) 
            {
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.GetAttribute(name);
            } 
            else
            { 
                SaveReaderPosition(); 

                // move to "name" attribute 
                if (MoveToAttribute(name))
                {
                    result = Reader.Value;
                    RestoreReaderPosition(); 
                }
            } 
 
            return result;
        } 

        /// 
        /// Gets the value of the attribute with the specified local name and namespace URI.
        ///  
        /// 
        /// The local name of the attribute. 
        ///  
        /// 
        /// The namespace URI of the attribute. 
        /// 
        /// 
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned.
        ///  
        public override string GetAttribute(string localName, string namespaceURI)
        { 
            string result = null; 

            if (_ignoredAttributeCount == 0 || !ShouldIgnoreNamespace(namespaceURI) ) 
            {
                // if the current element does not have any attributes that should be ignored or
                // the namespace provided is not ignorable, call Reader method
                result = Reader.GetAttribute(localName, namespaceURI); 
            }
 
            return result; 
        }
 
        /// 
        /// Gets the value of the attribute with the specified index.
        /// 
        ///  
        /// The index of the attribute. The index is zero-based. (The first attribute has index 0.)
        ///  
        ///  
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change.
        ///  
        public override void MoveToAttribute(int i)
        {
            if (_ignoredAttributeCount == 0)
            { 
                // if the current element should not ignored any attributes, call Reader method
                Reader.MoveToAttribute(i); 
            } 
            else if (i < 0 || i >= AttributeCount)
            { 
                throw new ArgumentOutOfRangeException("i");
            }
            else
            { 
                // move Reader to first attribute and iterate until 'i'th element found
                Reader.MoveToFirstAttribute(); 
 
                while (true)
                { 
                    if (!ShouldIgnoreNamespace(NamespaceURI))
                    {
                        // if attribute should not be ignored, decrement 'i', if i == 0 we've found element
                        if (i-- == 0) 
                        {
                            break; 
                        } 
                    }
 
                    Reader.MoveToNextAttribute();
                }
            }
        } 

        ///  
        /// Moves to the attribute with the specified name. 
        /// 
        ///  
        /// The qualified name of the attribute.
        /// 
        /// 
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change. 
        /// 
        public override bool MoveToAttribute(string name) 
        { 
            bool result;
 
            if (_ignoredAttributeCount == 0)
            {
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.MoveToAttribute(name); 
            }
            else 
            { 
                SaveReaderPosition();
 
                result = Reader.MoveToAttribute(name);
                if (result && ShouldIgnoreNamespace(NamespaceURI))
                {
                    // if attribute should be ignored, return false and restore state 
                    result = false;
                    RestoreReaderPosition(); 
                } 
            }
 
            return result;
        }

        ///  
        /// Moves to the attribute with the specified local name and namespace URI.
        ///  
        ///  
        /// The local name of the attribute.
        ///  
        /// 
        /// The namespace URI of the attribute.
        /// 
        ///  
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change.
        ///  
        public override bool MoveToAttribute(string localName, string namespaceURI) 
        {
            bool result; 

            if (_ignoredAttributeCount == 0)
            {
                // if the current element should not ignored any attributes, call Reader method 
                result = Reader.MoveToAttribute(localName, namespaceURI);
            } 
            else 
            {
                SaveReaderPosition(); 

                result = Reader.MoveToAttribute(localName, namespaceURI);

                if (result && ShouldIgnoreNamespace(namespaceURI)) 
                {
                    result = false; 
                    RestoreReaderPosition(); 
                }
            } 
            return result;
        }

        ///  
        /// Moves to the first attribute.
        ///  
        ///  
        /// true if an attribute exists (the reader moves to the first attribute);
        /// otherwise, false (the position of the reader does not change). 
        /// 
        public override bool MoveToFirstAttribute()
        {
            bool result = HasAttributes; 

            if(result) 
            { 
                MoveToAttribute(0);
            } 

            return result;
        }
 
        /// 
        /// Moves to the next attribute. 
        ///  
        /// 
        /// true if there is a next attribute; false if there are no more attributes. 
        /// 
        public override bool MoveToNextAttribute()
        {
            bool result; 

            if (_ignoredAttributeCount == 0) 
            { 
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.MoveToNextAttribute(); 
            }
            else
            {
                SaveReaderPosition(); 

                result = Reader.MoveToNextAttribute(); 
 
                if (result)
                { 
                    result = SkipToKnownAttribute();

                    if (!result)
                    { 
                        // if no more attributes exist that should not be ignored, return false and restore state
                        RestoreReaderPosition(); 
                    } 
                }
            } 

            return result;
        }
 
        /// 
        /// Resolves a namespace prefix in the current element's scope. 
        ///  
        /// 
        /// The prefix whose namespace URI you want to resolve. To match the default namespace, 
        /// pass an empty string. This string does not have to be atomized.
        /// 
        /// 
        /// The namespace URI to which the prefix maps or a null reference if no matching prefix is found. 
        /// 
        public override string LookupNamespace (string prefix) 
        { 
            string namespaceName = Reader.LookupNamespace(prefix);
 
            if (namespaceName != null)
            {
                namespaceName = GetMappedNamespace(namespaceName);
            } 

            return namespaceName; 
        } 

        #endregion Public Methods 

        #region Public Properties

        ///  
        /// This override is to ensure that the value
        /// for the xmlns attribute reflects all the 
        /// compatibility (subsuming) rules. 
        /// 
        public override string Value 
        {
            get
            {
                // Look for xmlns 
                if (String.Equals(XmlnsDeclaration, Reader.LocalName, StringComparison.Ordinal))
                { 
                    return LookupNamespace(String.Empty); 
                }
                // Look for xmlns: ... 
                else if (String.Equals(XmlnsDeclaration, Reader.Prefix, StringComparison.Ordinal))
                {
                    return LookupNamespace(Reader.LocalName);
                } 

                return Reader.Value; 
            } 
        }
 
        /// 
        /// Gets the namespace URI (as defined in the W3C Namespace specification) of the node
        /// on which the reader is positioned.
        ///  
        public override string NamespaceURI
        { 
            get 
            {
                return GetMappedNamespace(Reader.NamespaceURI); 
            }
        }

        ///  
        /// Gets the depth of the current node in the XML document.
        ///  
        public override int Depth 
        {
            get 
            {
                return Reader.Depth - _depthOffset;
            }
        } 

        ///  
        /// Gets a value indicating whether the current node has any attributes 
        /// 
        public override bool HasAttributes 
        {
            get
            {
                return AttributeCount != 0; 
            }
        } 
 
        /// 
        /// Gets the number of attributes on the current node. 
        /// 
        public override int AttributeCount
        {
            get 
            {
                return Reader.AttributeCount - _ignoredAttributeCount; 
            } 
        }
 
        /// 
        /// Sets a value indicating whether to normalize white space and attribute values.
        /// 
        public bool Normalization 
        {
            set 
            { 
                XmlTextReader xmlTextReader = Reader as XmlTextReader;
 
                // review, what if not the XmlTextReader.
                if (null != xmlTextReader)
                {
                    xmlTextReader.Normalization = value; 
                }
            } 
        } 

#if !PBTCOMPILER 
        /// 
        /// Answer the encoding of the underlying xaml stream
        /// 
        internal System.Text.Encoding Encoding 
        {
            get 
            { 
                XmlTextReader textReader = Reader as XmlTextReader;
                if (textReader == null) 
                {
                    return new System.Text.UTF8Encoding(true,true);
                }
                else 
                {
                    return textReader.Encoding; 
                } 
            }
        } 
#endif
        #endregion Public Properties

        #region Private Methods 

        private void SaveReaderPosition() 
        { 
            // Save current state so we can go back to the same spot if this fails
            _inAttribute = (Reader.NodeType == XmlNodeType.Attribute); 
            _currentName = Reader.Name;
        }

        private void RestoreReaderPosition() 
        {
            // Restore reader state from SaveReaderPosition 
            if (_inAttribute) 
            {
                Reader.MoveToAttribute(_currentName); 
            }
            else
            {
                Reader.MoveToElement(); 
            }
        } 
 
        /// 
        /// Retrieves the correctly mapped namespace from the namespace provided 
        /// 
        /// 
        /// The name of the namespace to retrieve the mapping of
        ///  
        /// 
        /// The name of the mapped namespace. 
        ///  
        private string GetMappedNamespace(string namespaceName)
        { 
            string mappedNamespace;

            // if the namespace is not null, get the mapped namespace (which may be itself)
            if (!_namespaceMap.TryGetValue(namespaceName, out mappedNamespace)) 
            {
                // if the namespace has not yet been mapped, map it 
                mappedNamespace = MapNewNamespace(namespaceName); 
            }
            else if (mappedNamespace == null) 
            {
                // if the mapped namespace is null, then the namespace was not supported, just return
                // the given namespace
                mappedNamespace = namespaceName; 
            }
 
            return mappedNamespace; 
        }
 
        /// 
        /// Adds the namespace to the namespace map.  The default is to map the namespace to itself.
        /// The namespace is mapped to the value returned by the callback, if a callback exists and the
        /// callback returns a subsuming namespace. 
        /// 
        ///  
        /// The name of the namespace to be mapped. 
        /// 
        ///  
        /// The name of the mapped namespace.
        /// 
        private string MapNewNamespace(string namespaceName)
        { 
            if (_namespaceCallback != null)
            { 
                string mappedNamespace; 

                // the callback returns whether the namespace is supported, and mappedNamespace is the 
                // namespace subsuming the namespace passed in.
                bool isSupported = _namespaceCallback(namespaceName, out mappedNamespace);

                if (isSupported) 
                {
                    AddKnownNamespace(namespaceName); 
 
                    if(String.IsNullOrEmpty(mappedNamespace) || namespaceName == mappedNamespace)
                    { 
                        _namespaceMap[namespaceName] = namespaceName;
                    }
                    else
                    { 
                        // subsume namespace with mappedNamespace.
                        string tempNamespace; 
 
                        if (!_namespaceMap.TryGetValue(mappedNamespace, out tempNamespace))
                        { 
                            // mappedNamespace has not been mapped, so map it
                            tempNamespace = MapNewNamespace(mappedNamespace);
                        }
 
                        DeclareNamespaceCompatibility(tempNamespace, namespaceName);
                        namespaceName = tempNamespace; 
                    } 
                }
                else 
                {
                    // if the namespace is not supported, we enter null into the namespaceMap as a placeholder
                    // so that we do not call the callback again on this namespace.
                    _namespaceMap[namespaceName] = null; 
                }
            } 
 
            return namespaceName;
        } 

        /// 
        /// Used to determine whether a given namespace subsumes another namespace
        ///  
        /// 
        /// The name of the namespace to be checked. 
        ///  
        /// 
        /// true if the namespace subsumes another namespace; false otherwise 
        /// 
        private bool IsSubsumingNamespace(string namespaceName)
        {
            return _subsumingNamespaces.ContainsKey(namespaceName); 
        }
 
        ///  
        /// Used to specify that a namespace subsumes another namespace
        ///  
        /// 
        /// The name of the namespace to be added.
        /// 
        private void AddSubsumingNamespace(string namespaceName) 
        {
            _subsumingNamespaces[namespaceName] = null; 
        } 

        ///  
        /// Used to determine whether a given namespace is known/supported
        /// 
        /// 
        /// The name of the namespace to be checked. 
        /// 
        ///  
        /// true if the namespace is known/supported; false otherwise 
        /// 
        private bool IsNamespaceKnown(string namespaceName) 
        {
            return _knownNamespaces.ContainsKey(namespaceName);
        }
 
        /// 
        /// Used to specify that a namespace is known or supported 
        ///  
        /// 
        /// The name of the namespace to be added. 
        /// 
        private void AddKnownNamespace(string namespaceName)
        {
            _knownNamespaces[namespaceName] = null; 
        }
 
        ///  
        /// Used to determine whether a given namespace should be ignored.  A namespace should be ignored if:
        /// EITHER 
        /// a) the namespace is not known/supported and has been marked Ignorable
        /// OR
        /// b) the namespace is the markup-compatibility namespace
        ///  
        /// 
        /// The name of the prefix to be checked. 
        ///  
        /// 
        /// true if the namespace should be ignored; false otherwise 
        /// 
        private bool ShouldIgnoreNamespace(string namespaceName)
        {
            bool result; 
            if(IsNamespaceKnown(namespaceName))
            { 
                result = object.ReferenceEquals(namespaceName, CompatibilityUri); 
            }
            else 
            {
                result = Scope.CanIgnore(namespaceName);
            }
            return result; 
        }
 
        ///  
        /// breaks up a space-delineated string into namespace/element pairs
        ///  
        /// 
        /// the string to be parsed
        /// 
        ///  
        /// The calling element, used in case of an error
        ///  
        ///  
        /// the list of namespace/element pairs
        ///  
        private IEnumerable ParseContentToNamespaceElementPair(string content, string callerContext)
        {
            foreach (string pair in content.Trim().Split(' '))
            { 
                // check each non-null, non-empty space-delineated namespace/element pair
                if(!String.IsNullOrEmpty(pair)) 
                { 
                    int colonIndex = pair.IndexOf(':');
                    int length = pair.Length; 

                    if(colonIndex <= 0 || colonIndex >= length - 1 || colonIndex != pair.LastIndexOf(':'))
                    {
                        // if string does not have a ':', if the last character in the string is a ':' 
                        // or if the string contains more than one ':', throw an exception
                        Error(SR.Get(SRID.XCRInvalidFormat), callerContext); 
                    } 

                    string prefix = pair.Substring(0, colonIndex); 
                    string elementName = pair.Substring(colonIndex + 1, length - 1 - colonIndex);
                    string namespaceName = LookupNamespace(prefix);

                    if (namespaceName == null) 
                    {
                        // if a prefix does not map to a namespace, throw an exception 
                        Error(SR.Get(SRID.XCRUndefinedPrefix), prefix); 
                    }
                    else if (elementName != "*" && !IsName(elementName)) 
                    {
                        // if the element's name is not valid XML, throw an exception
                        Error(SR.Get(SRID.XCRInvalidXMLName), pair);
                    } 
                    else
                    { 
                        yield return new NamespaceElementPair(namespaceName, elementName); 
                    }
                } 
            }
        }

        ///  
        /// converts a string of space-delineated prefixes into a list of namespaces
        ///  
        ///  
        /// the string to be parsed
        ///  
        /// 
        /// the list of namespace/element pairs
        /// 
        private IEnumerable PrefixesToNamespaces(string prefixes) 
        {
            foreach (string prefix in prefixes.Trim().Split(' ')) 
            { 
                // check each non-null, non-empty space-delineated prefix
                if(!String.IsNullOrEmpty(prefix)) 
                {
                    string namespaceUri = LookupNamespace(prefix);

                    if (namespaceUri == null) 
                    {
                        // if a prefix does not map to a namespace, throw an exception 
                        Error(SR.Get(SRID.XCRUndefinedPrefix), prefix); 
                    }
                    else 
                    {
                        yield return namespaceUri;
                    }
                } 
            }
        } 
 
        /// 
        /// advances the reader to the next known namespace/attribute pair 
        /// 
        /// 
        /// true if a known namespace/attribute pair was found
        ///  
        private bool SkipToKnownAttribute()
        { 
            bool result = true; 
            while (result && ShouldIgnoreNamespace(NamespaceURI))
            { 
                result = Reader.MoveToNextAttribute();
            }
            return result;
        } 

        ///  
        /// Scans the current element for compatibility attributes.  Pushes a new 
        /// scope onto the stack under the following conditions:
        /// 1) Ignorable or MustUnderstand attribute read 
        /// 2) current element has not previously declared an Ignorable or
        ///    MustUnderstand attribute
        ///
        /// However, if a last condition is not fulfilled, then the scope is popped off 
        /// before the function returns
        /// 3) current element is not empty 
        /// 
        /// stores in _ignoredAttributeCount the number of attributes on the current element
        /// that should be ignored, for the sake of improving perf in attribute-related 
        /// methods/properties
        /// 
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        private void ScanForCompatibility(int elementDepth) 
        { 
            bool onAttribute = Reader.MoveToFirstAttribute();
 
            _ignoredAttributeCount = 0;

            if (onAttribute)
            { 
                _attributePosition = 0; // we count the attribute index in case we see Ignorable
 
                do 
                {
                    string namespaceName = NamespaceURI; 

                    if(ShouldIgnoreNamespace(namespaceName))
                    {
                        // check each attribute's namespace to see if it should be ignored 
                        if (object.ReferenceEquals(namespaceName, CompatibilityUri))
                        { 
                            // if the attribute is in the markup-compatibility namespace 
                            // find and call the appropriate attribute handler callback.
                            string attributeName = Reader.LocalName; 
                            HandleAttributeCallback attributeCB;
                            if(!_attributeHandler.TryGetValue(attributeName, out attributeCB))
                            {
                                Error(SR.Get(SRID.XCRUnknownCompatAttrib), attributeName); 
                            }
                            attributeCB(elementDepth); 
                        } 

                        _ignoredAttributeCount++; 
                    }

                    onAttribute = Reader.MoveToNextAttribute();
                    _attributePosition++; // we count the attribute index in case we see Ignorable 
                } while (onAttribute);
 
                if (Scope.Depth == elementDepth) 
                {
                    // if this element pushed a scope, then we need to do a sanity check 
                    Scope.Verify();
                }

                // move the reader back to the element for the client 
                Reader.MoveToElement();
            } 
        } 

 
        /// 
        /// pops a scope if the end of a compatibility region.
        /// 
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        private void ScanForEndCompatibility(int elementDepth) 
        {
            if (elementDepth == Scope.Depth) 
            {
                // if the current element's depth equals the depth of the top-level scope, then pop
                PopScope();
            } 
        }
 
        ///  
        /// pushes a new scope onto the stack with a depth passed as an arg.
        /// PushScope does not push a scope if the top scope on the stack is not a lower depth. 
        /// 
        /// 
        /// the depth of the Reader at the element currently being processed
        ///  
        private void PushScope(int elementDepth)
        { 
            if(_compatibilityScope.Depth < elementDepth) 
            {
                // if the current element has already pushed a scope, then don't push another one 
                _compatibilityScope = new CompatibilityScope(_compatibilityScope, elementDepth, this);
            }
        }
 
        /// 
        /// pops a scope off the top of the stack. 
        /// PopScope *always* pops, it does not check the depth before doing so 
        /// 
        private void PopScope() 
        {
            _compatibilityScope = _compatibilityScope.Previous;
        }
 
        /// 
        /// handles mc:AlternateContent element 
        /// 
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        /// 
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        ///  
        /// returns whether the Reader has more to be read 
        /// 
        private void HandleAlternateContent(int elementDepth, ref bool more) 
        {
            if (Scope.InAlternateContent)
            {
                // the only valid tags within  ...  are 
                // Choice and Fallback
                Error(SR.Get(SRID.XCRInvalidACChild, Reader.Name)); 
            } 
            if(Reader.IsEmptyElement)
            { 
                // AlternateContent blocks must have a Choice, so they can't be empty
                Error(SR.Get(SRID.XCRChoiceNotFound));
            }
 
            // check for markup-compatibility attributes, then push an AlternateContent scope
            ScanForCompatibility(elementDepth); 
            PushScope(elementDepth); 

            Scope.InAlternateContent = true; 
            _depthOffset++;
            more = Reader.Read();
        }
 
        /// 
        /// handles mc:Choice element 
        /// 
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        /// 
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        ///  
        /// returns whether the Reader has more to be read 
        /// 
        private void HandleChoice(int elementDepth, ref bool more) 
        {
            if (!Scope.InAlternateContent)
            {
                // Choice must be the child of AlternateContent 
                Error(SR.Get(SRID.XCRChoiceOnlyInAC));
            } 
            if (Scope.FallbackSeen) 
            {
                // Choice cannot occur after Fallback 
                Error(SR.Get(SRID.XCRChoiceAfterFallback));
            }

            string requiresValue = Reader.GetAttribute(Requires); 

            if (requiresValue == null) 
            { 
                // Choice must have a requires attribute
                Error(SR.Get(SRID.XCRRequiresAttribNotFound)); 
            }
            if (String.IsNullOrEmpty(requiresValue))
            {
                // Requires attribute may not be empty 
                Error(SR.Get(SRID.XCRInvalidRequiresAttribute));
            } 
 
            CompatibilityScope scope = Scope;
 
            // check for markup-compatibility attributes
            ScanForCompatibility(elementDepth);

            if (AttributeCount != 1) 
            {
                // Choice may not have any attribute that should not be ignored other than Requires 
                // get first non-markup-compatibility, non-Requires attribute 
                MoveToFirstAttribute();
                if(Reader.LocalName == Requires) 
                {
                    MoveToNextAttribute();
                }
                string attributeName = Reader.LocalName; 
                MoveToElement();
 
                Error(SR.Get(SRID.XCRInvalidAttribInElement), attributeName, Choice); 
            }
 
            if (scope.ChoiceTaken)
            {
                // a previous choice was valid, so pop any scope pushed and
                // skip to next attribute after  
                ScanForEndCompatibility(elementDepth);
                Reader.Skip(); 
            } 
            else
            { 
                // mark AlternateContent as having seen a choice
                scope.ChoiceSeen = true;

                bool allKnown = true; 
                bool somethingSeen = false;
 
                foreach (string namespaceUri in PrefixesToNamespaces(requiresValue)) 
                {
                    somethingSeen = true; 
                    if (!IsNamespaceKnown(namespaceUri))
                    {
                        // if any attribute in the Requires value is unknown, then do not take this choice
                        allKnown = false; 
                        break;
                    } 
                } 

                if (!somethingSeen) 
                {
                    // if the Requires value does not contain a valid prefix/namespace, throw an exception
                    Error(SR.Get(SRID.XCRInvalidRequiresAttribute));
                } 

                if (allKnown) 
                { 
                    // if all namespace in the Requires value are known, then this is the Choice taken.
                    // Mark AlternateContent scope as having taken a choice 
                    scope.ChoiceTaken = true;

                    // we push a scope here as a place holder, because AlternateContent
                    // scopes do not allow child elements other than Choice and Fallback 
                    PushScope(elementDepth);
                    _depthOffset++; 
                    more = Reader.Read(); 
                }
                else 
                {
                    // this is not the choice taken, so pop any scope pushed and
                    // skip to next attribute after 
                    ScanForEndCompatibility(elementDepth); 
                    Reader.Skip();
                } 
            } 
        }
 
        /// 
        /// handles mc:Fallback element
        ///
        /// a good way to think of AlternateContent blocks is as a switch/case 
        /// statement.  The AlternateContent tag is like switch, Choice is like
        /// case, and Fallback is like default. 
        ///  
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        /// 
        /// returns whether the Reader has more to be read
        ///  
        private void HandleFallback(int elementDepth, ref bool more)
        { 
            if (!Scope.InAlternateContent) 
            {
                // Fallback must be the child of AlternateContent 
                Error(SR.Get(SRID.XCRFallbackOnlyInAC));
            }
            if (!Scope.ChoiceSeen)
            { 
                // AlternateContent block must contain a Choice element
                Error(SR.Get(SRID.XCRChoiceNotFound)); 
            } 
            if (Scope.FallbackSeen)
            { 
                // AlternateContent block may only contain one Fallback child
                Error(SR.Get(SRID.XCRMultipleFallbackFound));
            }
 
            // mark scope as having a fallback
            Scope.FallbackSeen = true; 
            bool choiceTaken = Scope.ChoiceTaken; 

            // check for markup-compatibility attributes 
            ScanForCompatibility(elementDepth);

            if (AttributeCount != 0)
            { 
                // Fallback may not have any attribute that should not be ignored
                // get first non-markup-compatibility attribute 
                MoveToFirstAttribute(); 
                string attributeName = Reader.LocalName;
                MoveToElement(); 

                Error(SR.Get(SRID.XCRInvalidAttribInElement), attributeName, Fallback);
            }
 
            if (choiceTaken)
            { 
                // a choice was valid, so ignore contents 
                ScanForEndCompatibility(elementDepth);
                Reader.Skip(); 
            }
            else
            {
                // this is the content that will be used, so push a scope 
                if(!Reader.IsEmptyElement)
                { 
                    // we push a scope here as a place holder, because AlternateContent 
                    // scopes do not allow child elements other than Choice and Fallback
                    PushScope(elementDepth); 
                    _depthOffset++;
                }
                more = Reader.Read();
            } 
        }
 
        ///  
        /// handles mc:Ignorable="foo" attribute
        /// 
        /// Ignorable is used to indicate that the namespace the prefix is mapped to can
        /// be ignored, i.e. when the namespace/element or namespace/attribute occurs it
        /// is not returned by the reader.
        ///  
        private void HandleIgnorable(int elementDepth)
        { 
            PushScope(elementDepth); 

            foreach (string namespaceUri in PrefixesToNamespaces(Reader.Value)) 
            {
                Scope.Ignorable(namespaceUri);
            }
 
            // Just in case one of the namespaces that preceded the Ignorable declaration
            // was an ignorable namespace, we have to recompute _ignoredAttributeCount :� . 
            // No need to check if we haven't yet had any non-ignored attributes. 
            if (_ignoredAttributeCount < _attributePosition)
            { 
                _ignoredAttributeCount = 0;
                Reader.MoveToFirstAttribute();

                for (int i = 0; i < _attributePosition; i++) 
                {
                    if (ShouldIgnoreNamespace(Reader.NamespaceURI)) 
                    { 
                        _ignoredAttributeCount++;
                    } 

                    Reader.MoveToNextAttribute();
                }
            } 
        }
 
        ///  
        /// handles mc:MustUnderstand="foo" attribute
        /// 
        /// MustUnderstand is used to indicate that the namespace the prefix is mapped to
        /// cannot be handled, and if it is not understood an exception is thrown
        /// 
        private void HandleMustUnderstand(int elementDepth) 
        {
            foreach (string namespaceUri in PrefixesToNamespaces(Reader.Value)) 
            { 
                if (!IsNamespaceKnown(namespaceUri))
                { 
                    Error(SR.Get(SRID.XCRMustUnderstandFailed), namespaceUri);
                }
            }
        } 

        ///  
        /// handles mc:ProcessContent="foo:bar" attribute 
        ///
        /// ProcessContent is used to indicate that an ignorable namespace has some 
        /// elements that should be skipped, but contain child elements that should be processed.
        ///
        /// The wildcard token ("foo:*") indicates that the children of any element in that
        /// namespace should be processed. 
        /// 
        private void HandleProcessContent(int elementDepth) 
        { 
            PushScope(elementDepth);
 
            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _processContent))
            {
                Scope.ProcessContent(pair.namespaceName, pair.itemName);
            } 
        }
 
        ///  
        /// handles mc:PreserveElements="foo:bar" attribute
        /// 
        /// functionality is supported, but not implemented
        /// 
        private void HandlePreserveElements(int elementDepth)
        { 
            PushScope(elementDepth);
 
            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _preserveElements)) 
            {
                Scope.PreserveElement(pair.namespaceName, pair.itemName); 
            }
        }

        ///  
        /// handles mc:PreserveAttributes="foo:bar" attribute
        /// 
        /// functionality is supported, but not implemented 
        /// 
        private void HandlePreserveAttributes(int elementDepth) 
        {
            PushScope(elementDepth);

            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _preserveAttributes)) 
            {
                Scope.PreserveAttribute(pair.namespaceName, pair.itemName); 
            } 
        }
 
        /// 
        /// helper method to generate an exception
        /// 
        private void Error(string message, params object[] args) 
        {
            IXmlLineInfo info = Reader as IXmlLineInfo; 
            throw new XmlException(string.Format(CultureInfo.InvariantCulture, message, args), null, info == null ? 1 : info.LineNumber, 
                info == null ? 1 : info.LinePosition);
        } 
        #endregion Private Methods

        #region Private Properties
        private CompatibilityScope Scope 
        {
            get 
            { 
                return _compatibilityScope;
            } 
        }

        private string AlternateContent
        { 
            get
            { 
                if (_alternateContent == null) 
                {
                    _alternateContent = Reader.NameTable.Add("AlternateContent"); 
                }
                return _alternateContent;
            }
        } 

        private string Choice 
        { 
            get
            { 
                if (_choice == null)
                {
                    _choice = Reader.NameTable.Add("Choice");
                } 
                return _choice;
            } 
        } 

        private string Fallback 
        {
            get
            {
                if (_fallback == null) 
                {
                    _fallback = Reader.NameTable.Add("Fallback"); 
                } 
                return _fallback;
            } 
        }

        private string Requires
        { 
            get
            { 
                if (_requires == null) 
                {
                    _requires = Reader.NameTable.Add("Requires"); 
                }
                return _requires;
            }
        } 

        private string Ignorable 
        { 
            get
            { 
                if(_ignorable == null)
                {
                    _ignorable = Reader.NameTable.Add("Ignorable");
                } 
                return _ignorable;
            } 
        } 

        private string MustUnderstand 
        {
            get
            {
                if(_mustUnderstand == null) 
                {
                    _mustUnderstand = Reader.NameTable.Add("MustUnderstand"); 
                } 
                return _mustUnderstand;
            } 
        }

        private string ProcessContent
        { 
            get
            { 
                if(_processContent == null) 
                {
                    _processContent = Reader.NameTable.Add("ProcessContent"); 
                }
                return _processContent;
            }
        } 

        private string PreserveElements 
        { 
            get
            { 
                if(_preserveElements == null)
                {
                    _preserveElements = Reader.NameTable.Add("PreserveElements");
                } 
                return _preserveElements;
            } 
        } 

        private string PreserveAttributes 
        {
            get
            {
                if(_preserveAttributes == null) 
                {
                    _preserveAttributes = Reader.NameTable.Add("PreserveAttributes"); 
                } 
                return _preserveAttributes;
            } 
        }

        private string CompatibilityUri
        { 
            get
            { 
                if (_compatibilityUri == null) 
                {
                    _compatibilityUri = Reader.NameTable.Add(MarkupCompatibilityURI); 
                }
                return _compatibilityUri;
            }
        } 
        #endregion Private Properties
        #region Nested Classes 
        struct NamespaceElementPair 
        {
            public string namespaceName; 
            public string itemName;

            public NamespaceElementPair(string namespaceName, string itemName)
            { 
                this.namespaceName = namespaceName;
                this.itemName = itemName; 
            } 
        }
 
        /// 
        /// CompatibilityScopes are used to handle markup-compatibility elements and attributes.
        /// Each scope stores the "previous" or parent scope, its depth, and an associated XmlCompatibilityReader.
        /// At a particular Reader depth, only one scope should be pushed. 
        /// 
        private class CompatibilityScope 
        { 
            CompatibilityScope _previous;
            int _depth; 
            bool _fallbackSeen;
            bool _inAlternateContent;
            bool _inProcessContent;
            bool _choiceTaken; 
            bool _choiceSeen;
            XmlCompatibilityReader _reader; 
            Dictionary _ignorables; 
            Dictionary _processContents;
            Dictionary _preserveElements; 
            Dictionary _preserveAttributes;

            public CompatibilityScope(CompatibilityScope previous, int depth, XmlCompatibilityReader reader)
            { 
                _previous = previous;
                _depth = depth; 
                _reader = reader; 
            }
 
            public CompatibilityScope Previous
            {
                get
                { 
                    return _previous;
                } 
            } 

            public int Depth 
            {
                get
                {
                    return _depth; 
                }
            } 
 
            public bool FallbackSeen
            { 
                get
                {
                    bool result;
                    if(_inProcessContent && _previous != null) 
                    {
                        result = _previous.FallbackSeen; 
                    } 
                    else
                    { 
                        result = _fallbackSeen;
                    }
                    return result;
                } 
                set
                { 
                    if(_inProcessContent && _previous != null) 
                    {
                        _previous.FallbackSeen = value; 
                    }
                    else
                    {
                        _fallbackSeen = value; 
                    }
                } 
            } 

            public bool InAlternateContent 
            {
                get
                {
                    bool result; 
                    if(_inProcessContent && _previous != null)
                    { 
                        result = _previous.InAlternateContent; 
                    }
                    else 
                    {
                        result = _inAlternateContent;
                    }
                    return result; 
                }
                set 
                { 
                    _inAlternateContent = value;
                } 
            }

            public bool InProcessContent
            { 
                set
                { 
                    _inProcessContent = value; 
                }
            } 

            public bool ChoiceTaken
            {
                get 
                {
                    bool result; 
                    if(_inProcessContent && _previous != null) 
                    {
                        result = _previous.ChoiceTaken; 
                    }
                    else
                    {
                        result = _choiceTaken; 
                    }
                    return result; 
                } 
                set
                { 
                    if(_inProcessContent && _previous != null)
                    {
                        _previous.ChoiceTaken = value;
                    } 
                    else
                    { 
                        _choiceTaken = value; 
                    }
                } 
            }

            public bool ChoiceSeen
            { 
                get
                { 
                    bool result; 
                    if(_inProcessContent && _previous != null)
                    { 
                        result = _previous.ChoiceSeen;
                    }
                    else
                    { 
                        result = _choiceSeen;
                    } 
                    return result; 
                }
                set 
                {
                    if(_inProcessContent && _previous != null)
                    {
                        _previous.ChoiceSeen = value; 
                    }
                    else 
                    { 
                        _choiceSeen = value;
                    } 
                }
            }

            public bool CanIgnore(string namespaceName) 
            {
                bool result = IsIgnorableAtCurrentScope(namespaceName); 
 
                if (!result && _previous != null)
                { 
                    result = _previous.CanIgnore(namespaceName);
                }

                return result; 
            }
 
            public bool IsIgnorableAtCurrentScope(string namespaceName) 
            {
                return _ignorables != null && _ignorables.ContainsKey(namespaceName); 
            }

            public bool ShouldProcessContent(string namespaceName, string elementName)
            { 
                bool result = false;
                ProcessContentSet set; 
                if (_processContents != null && _processContents.TryGetValue(namespaceName, out set)) 
                {
                    result = set.ShouldProcessContent(elementName); 
                }
                else if (_previous != null)
                {
                    result = _previous.ShouldProcessContent(namespaceName, elementName); 
                }
 
                return result; 
            }
 
            public void Ignorable(string namespaceName)
            {
                if (_ignorables == null)
                { 
                    _ignorables = new Dictionary();
                } 
                _ignorables[namespaceName] = null; // we don't care about value, just key 
            }
 
            public void ProcessContent(string namespaceName, string elementName)
            {
                if (_processContents == null)
                { 
                    _processContents = new Dictionary();
                } 
                ProcessContentSet processContentSet; 
                if (!_processContents.TryGetValue(namespaceName, out processContentSet))
                { 
                    processContentSet = new ProcessContentSet(namespaceName, _reader);
                    _processContents.Add(namespaceName, processContentSet);
                }
                processContentSet.Add(elementName); 
            }
 
            public void PreserveElement(string namespaceName, string elementName) 
            {
                if (_preserveElements == null) 
                {
                    _preserveElements = new Dictionary();
                }
                PreserveItemSet preserveElementSet; 
                if (!_preserveElements.TryGetValue(namespaceName, out preserveElementSet))
                { 
                    preserveElementSet = new PreserveItemSet(namespaceName, _reader); 
                    _preserveElements.Add(namespaceName, preserveElementSet);
                } 
                preserveElementSet.Add(elementName);
            }

            public void PreserveAttribute(string namespaceName, string attributeName) 
            {
                if (_preserveAttributes == null) 
                { 
                    _preserveAttributes = new Dictionary();
                } 
                PreserveItemSet preserveAttributeSet;
                if (!_preserveAttributes.TryGetValue(namespaceName, out preserveAttributeSet))
                {
                    preserveAttributeSet = new PreserveItemSet(namespaceName, _reader); 
                    _preserveAttributes.Add(namespaceName, preserveAttributeSet);
                } 
                preserveAttributeSet.Add(attributeName); 
            }
 
            /*public bool ShouldPreserveElement(string namespaceName, string elementName)
            {
                bool result = _preserveItems != null && _preserveItems.ShouldPreserveElement(namespaceName, elementName);
                if (!result && _previous != null) 
                    result = _previous.ShouldPreserveElement(namespaceName, elementName);
                return result; 
            } 

            public bool ShouldPreserveAttribute(string namespaceName, string attributeName) 
            {
                bool result = _preserveItems != null && _preserveItems.ShouldPreserveAttribute(namespaceName, attributeName);
                if (!result && _previous != null)
                    result = _previous.ShouldPreserveAttribute(namespaceName, attributeName); 
                return result;
            }*/ 
 
            public void Verify()
            { 
                // Check process content
                if (_processContents != null)
                {
                    foreach (string key in _processContents.Keys) 
                    {
                        if (!IsIgnorableAtCurrentScope(key)) 
                        { 
                            _reader.Error(SR.Get(SRID.XCRNSProcessContentNotIgnorable), key);
                        } 
                    }
                }
                // Check preserve elements
                if (_preserveElements != null) 
                {
                    foreach (string key in _preserveElements.Keys) 
                    { 
                        if (!IsIgnorableAtCurrentScope(key))
                        { 
                            _reader.Error(SR.Get(SRID.XCRNSPreserveNotIgnorable), key);
                        }
                    }
                } 
                // Check preserve attributes
                if (_preserveAttributes != null) 
                { 
                    foreach (string key in _preserveAttributes.Keys)
                    { 
                        if (!IsIgnorableAtCurrentScope(key))
                        {
                            _reader.Error(SR.Get(SRID.XCRNSPreserveNotIgnorable), key);
                        } 
                    }
                } 
            } 
        }
 
        class ProcessContentSet
        {
            bool _all;
            string _namespaceName; 
            XmlCompatibilityReader _reader;
            Dictionary _names; 
 
            public ProcessContentSet(string namespaceName, XmlCompatibilityReader reader)
            { 
                _namespaceName = namespaceName;
                _reader = reader;
            }
 
            public bool ShouldProcessContent(string elementName)
            { 
                return _all || (_names != null && _names.ContainsKey(elementName)); 
            }
 
            public void Add(string elementName)
            {
                if (ShouldProcessContent(elementName))
                { 
                    if (elementName == "*")
                    { 
                        _reader.Error(SR.Get(SRID.XCRDuplicateWildcardProcessContent), _namespaceName); 
                    }
                    else 
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateProcessContent), _namespaceName, elementName);
                    }
                } 

                if (elementName == "*") 
                { 
                    if (_names != null)
                    { 
                        _reader.Error(SR.Get(SRID.XCRInvalidProcessContent), _namespaceName);
                    }
                    else
                    { 
                        _all = true;
                    } 
                } 
                else
                { 
                    if (_names == null)
                    {
                        _names = new Dictionary();
                    } 

                    _names[elementName] = null; // we don't care about value, just key 
                } 
            }
 
        }

        class PreserveItemSet
        { 
            bool _all;
            string _namespaceName; 
            XmlCompatibilityReader _reader; 
            Dictionary _names;
 
            public PreserveItemSet(string namespaceName, XmlCompatibilityReader reader)
            {
                _namespaceName = namespaceName;
                _reader = reader; 
            }
 
            public bool ShouldPreserveItem(string itemName) 
            {
                return _all || (_names != null && _names.ContainsKey(itemName)); 
            }

            public void Add(string itemName)
            { 
                if (ShouldPreserveItem(itemName))
                { 
                    if (itemName == "*") 
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateWildcardPreserve), _namespaceName); 
                    }
                    else
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicatePreserve), itemName, _namespaceName); 
                    }
                } 
 
                if (itemName == "*")
                { 
                    if (_names != null)
                    {
                        _reader.Error(SR.Get(SRID.XCRInvalidPreserve), _namespaceName);
                    } 
                    else
                    { 
                        _all = true; 
                    }
                } 
                else
                {
                    if (_names == null)
                    { 
                        _names = new Dictionary();
                    } 
 
                    _names.Add(itemName, itemName);
                } 
            }
        }
        #endregion Nested Classes
 
        #region Private Fields
        private bool _inAttribute; // for Save/Restore ReaderPosition 
        private string _currentName; // for Save/Restore ReaderPosition 
        private IsXmlNamespaceSupportedCallback _namespaceCallback;
        private Dictionary _knownNamespaces = new Dictionary(); 
        private Dictionary _namespaceMap = new Dictionary();
        private Dictionary _subsumingNamespaces = new Dictionary();
        private Dictionary _elementHandler = new Dictionary();
        private Dictionary _attributeHandler = new Dictionary(); 
        private int _depthOffset; // offset for Depth method, to account for elements that should be ignored by client
        private int _ignoredAttributeCount; 
        private int _attributePosition; // used for ScanForCompatibility / HandleIgnorable 
        private string _compatibilityUri;
        private string _alternateContent; 
        private string _choice;
        private string _fallback;
        private string _requires;
        private string _ignorable; 
        private string _mustUnderstand;
        private string _processContent; 
        private string _preserveElements; 
        private string _preserveAttributes;
        private CompatibilityScope _compatibilityScope; 

        private const string XmlnsDeclaration = "xmlns";
        private const string MarkupCompatibilityURI = "http://schemas.openxmlformats.org/markup-compatibility/2006";
 
        static private string [] _predefinedNamespaces = new string [4] {
            "http://www.w3.org/2000/xmlns/", 
            "http://www.w3.org/XML/1998/namespace", 
            "http://www.w3.org/2001/XMLSchema-instance",
            MarkupCompatibilityURI 
        };
        #endregion Private Fields
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK