DocumentSchemaValidator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Xml / System / Xml / Dom / DocumentSchemaValidator.cs / 1305376 / DocumentSchemaValidator.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Text;
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Xml.Schema; 
using System.Xml.XPath;
using System.Globalization; 
using System.Security; 
using System.Security.Policy;
using System.Security.Permissions; 
using System.Reflection;
using System.Runtime.Versioning;

namespace System.Xml { 

    internal sealed class DocumentSchemaValidator : IXmlNamespaceResolver { 
        XmlSchemaValidator validator; 
        XmlSchemaSet schemas;
 
        XmlNamespaceManager nsManager;
        XmlNameTable nameTable;

        //Attributes 
        ArrayList defaultAttributes;
        XmlValueGetter nodeValueGetter; 
        XmlSchemaInfo attributeSchemaInfo; 

        //Element PSVI 
        XmlSchemaInfo schemaInfo;

        //Event Handler
        ValidationEventHandler eventHandler; 
        ValidationEventHandler internalEventHandler;
 
        //Store nodes 
        XmlNode startNode;
        XmlNode currentNode; 
        XmlDocument document;

        //List of nodes for partial validation tree walk
        XmlNode[] nodeSequenceToValidate; 
        bool isPartialTreeValid;
 
        bool psviAugmentation; 
        bool isValid;
 
        //To avoid SchemaNames creation
        private string NsXmlNs;
        private string NsXsi;
        private string XsiType; 
        private string XsiNil;
 
        public DocumentSchemaValidator(XmlDocument ownerDocument, XmlSchemaSet schemas, ValidationEventHandler eventHandler) { 
            this.schemas = schemas;
            this.eventHandler = eventHandler; 
            document = ownerDocument;
            this.internalEventHandler = new ValidationEventHandler(InternalValidationCallBack);

            this.nameTable = document.NameTable; 
            nsManager = new XmlNamespaceManager(nameTable);
 
            Debug.Assert(schemas != null && schemas.Count > 0); 

            nodeValueGetter = new XmlValueGetter(GetNodeValue); 
            psviAugmentation = true;

            //Add common strings to be compared to NameTable
            NsXmlNs = nameTable.Add(XmlReservedNs.NsXmlNs); 
            NsXsi = nameTable.Add(XmlReservedNs.NsXsi);
            XsiType = nameTable.Add("type"); 
            XsiNil = nameTable.Add("nil"); 
        }
 
        public bool PsviAugmentation {
            get { return psviAugmentation; }
            set { psviAugmentation = value; }
        } 

        public bool Validate(XmlNode nodeToValidate) { 
            XmlSchemaObject partialValidationType = null; 
            XmlSchemaValidationFlags validationFlags = XmlSchemaValidationFlags.AllowXmlAttributes;
            Debug.Assert(nodeToValidate.SchemaInfo != null); 

            startNode = nodeToValidate;
            switch (nodeToValidate.NodeType) {
                case XmlNodeType.Document: 
                    validationFlags |= XmlSchemaValidationFlags.ProcessIdentityConstraints;
                    break; 
 
                case XmlNodeType.DocumentFragment:
                    break; 

                case XmlNodeType.Element: //Validate children of this element
                    IXmlSchemaInfo schemaInfo = nodeToValidate.SchemaInfo;
                    XmlSchemaElement schemaElement = schemaInfo.SchemaElement; 
                    if (schemaElement != null) {
                        if (!schemaElement.RefName.IsEmpty) { //If it is element ref, 
                            partialValidationType = schemas.GlobalElements[schemaElement.QualifiedName]; //Get Global element with correct Nillable, Default etc 
                        }
                        else { //local element 
                            partialValidationType = schemaElement;
                        }
                        //Verify that if there was xsi:type, the schemaElement returned has the correct type set
                        Debug.Assert(schemaElement.ElementSchemaType == schemaInfo.SchemaType); 
                    }
                    else { //Can be an element that matched xs:any and had xsi:type 
                        partialValidationType = schemaInfo.SchemaType; 

                        if (partialValidationType == null) { //Validated against xs:any with pc= lax or skip or undeclared / not validated element 
                            if (nodeToValidate.ParentNode.NodeType == XmlNodeType.Document) {
                                //If this is the documentElement and it has not been validated at all
                                nodeToValidate = nodeToValidate.ParentNode;
                            } 
                            else {
                                partialValidationType = FindSchemaInfo(nodeToValidate as XmlElement); 
                                if (partialValidationType == null) { 
                                    throw new XmlSchemaValidationException(Res.XmlDocument_NoNodeSchemaInfo, null, nodeToValidate);
                                } 
                            }
                        }
                    }
                    break; 

                case XmlNodeType.Attribute: 
                    if (nodeToValidate.XPNodeType == XPathNodeType.Namespace) goto default; 
                    partialValidationType = nodeToValidate.SchemaInfo.SchemaAttribute;
                    if (partialValidationType == null) { //Validated against xs:anyAttribute with pc = lax or skip / undeclared attribute 
                        partialValidationType = FindSchemaInfo(nodeToValidate as XmlAttribute);
                        if (partialValidationType == null) {
                            throw new XmlSchemaValidationException(Res.XmlDocument_NoNodeSchemaInfo, null, nodeToValidate);
                        } 
                    }
                    break; 
 
                default:
                    throw new InvalidOperationException(Res.GetString(Res.XmlDocument_ValidateInvalidNodeType, null)); 
            }
            isValid = true;
            CreateValidator(partialValidationType, validationFlags);
            if (psviAugmentation) { 
                if (schemaInfo == null) { //Might have created it during FindSchemaInfo
                    schemaInfo = new XmlSchemaInfo(); 
                } 
                attributeSchemaInfo = new XmlSchemaInfo();
            } 
            ValidateNode(nodeToValidate);
            validator.EndValidation();
            return isValid;
        } 

        public IDictionary GetNamespacesInScope(XmlNamespaceScope scope) { 
            IDictionary dictionary = nsManager.GetNamespacesInScope(scope); 
            if (scope != XmlNamespaceScope.Local) {
                XmlNode node = startNode; 
                while (node != null) {
                    switch (node.NodeType) {
                        case XmlNodeType.Element:
                            XmlElement elem = (XmlElement)node; 
                            if (elem.HasAttributes) {
                                XmlAttributeCollection attrs = elem.Attributes; 
                                for (int i = 0; i < attrs.Count; i++) { 
                                    XmlAttribute attr = attrs[i];
                                    if (Ref.Equal(attr.NamespaceURI, document.strReservedXmlns)) { 
                                        if (attr.Prefix.Length == 0) {
                                            // xmlns='' declaration
                                            if (!dictionary.ContainsKey(string.Empty)) {
                                                dictionary.Add(string.Empty, attr.Value); 
                                            }
                                        } 
                                        else { 
                                            // xmlns:prefix='' declaration
                                            if (!dictionary.ContainsKey(attr.LocalName)) { 
                                                dictionary.Add(attr.LocalName, attr.Value);
                                            }
                                        }
                                    } 
                                }
                            } 
                            node = node.ParentNode; 
                            break;
                        case XmlNodeType.Attribute: 
                            node = ((XmlAttribute)node).OwnerElement;
                            break;
                        default:
                            node = node.ParentNode; 
                            break;
                    } 
                } 
            }
            return dictionary; 
        }

        public string LookupNamespace(string prefix) {
            string namespaceName = nsManager.LookupNamespace(prefix); 
            if (namespaceName == null) {
                namespaceName = startNode.GetNamespaceOfPrefixStrict(prefix); 
            } 
            return namespaceName;
        } 

        public string LookupPrefix(string namespaceName) {
            string prefix = nsManager.LookupPrefix(namespaceName);
            if (prefix == null) { 
                prefix = startNode.GetPrefixOfNamespaceStrict(namespaceName);
            } 
            return prefix; 
        }
 
        private IXmlNamespaceResolver NamespaceResolver {
            get {
                if ((object)startNode == (object)document) {
                    return nsManager; 
                }
                return this; 
            } 
        }
 
        private void CreateValidator(XmlSchemaObject partialValidationType, XmlSchemaValidationFlags validationFlags) {
            validator = new XmlSchemaValidator(nameTable, schemas, NamespaceResolver, validationFlags);
            validator.SourceUri = XmlConvert.ToUri(document.BaseURI);
            validator.XmlResolver = null; 
            validator.ValidationEventHandler += internalEventHandler;
            validator.ValidationEventSender = this; 
 
            if (partialValidationType != null) {
                validator.Initialize(partialValidationType); 
            }
            else {
                validator.Initialize();
            } 
        }
 
        private void ValidateNode(XmlNode node) { 
            currentNode = node;
            switch (currentNode.NodeType) { 
                case XmlNodeType.Document:
                    XmlElement docElem = ((XmlDocument)node).DocumentElement;
                    if (docElem == null) {
                        throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidXmlDocument, Res.GetString(Res.Xdom_NoRootEle))); 
                    }
                    ValidateNode(docElem); 
                    break; 

                case XmlNodeType.DocumentFragment: 
                case XmlNodeType.EntityReference:
                    for (XmlNode child = node.FirstChild; child != null; child = child.NextSibling) {
                        ValidateNode(child);
                    } 
                    break;
 
                case XmlNodeType.Element: 
                    ValidateElement();
                    break; 

                case XmlNodeType.Attribute: //Top-level attribute
                    XmlAttribute attr = currentNode as XmlAttribute;
                    validator.ValidateAttribute(attr.LocalName, attr.NamespaceURI, nodeValueGetter, attributeSchemaInfo); 
                    if (psviAugmentation) {
                        attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo); 
                    } 
                    break;
 
                case XmlNodeType.Text:
                    validator.ValidateText(nodeValueGetter);
                    break;
 
                case XmlNodeType.CDATA:
                    validator.ValidateText(nodeValueGetter); 
                    break; 

                case XmlNodeType.Whitespace: 
                case XmlNodeType.SignificantWhitespace:
                    validator.ValidateWhitespace(nodeValueGetter);
                    break;
 
                case XmlNodeType.Comment:
                case XmlNodeType.ProcessingInstruction: 
                    break; 

                default: 
                    throw new InvalidOperationException( Res.GetString( Res.Xml_UnexpectedNodeType, new string[]{ currentNode.NodeType.ToString() } ) );
            }
        }
 
        // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
        // Since the resource names passed to ValidateElement method are null and the function does not expose any resources 
        // it is fine to suppress the SxS warning. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)] 
        private void ValidateElement() {
            nsManager.PushScope();
            XmlElement elementNode = currentNode as XmlElement;
            Debug.Assert(elementNode != null); 

            XmlAttributeCollection attributes = elementNode.Attributes; 
            XmlAttribute attr = null; 

            //Find Xsi attributes that need to be processed before validating the element 
            string xsiNil = null;
            string xsiType = null;

            for (int i = 0; i < attributes.Count; i++) { 
                attr = attributes[i];
                string objectNs = attr.NamespaceURI; 
                string objectName = attr.LocalName; 
                Debug.Assert(nameTable.Get(attr.NamespaceURI) != null);
                Debug.Assert(nameTable.Get(attr.LocalName) != null); 

                if (Ref.Equal(objectNs, NsXsi)) {
                    if (Ref.Equal(objectName, XsiType)) {
                        xsiType = attr.Value; 
                    }
                    else if (Ref.Equal(objectName, XsiNil)) { 
                        xsiNil = attr.Value; 
                    }
                } 
                else if (Ref.Equal(objectNs,NsXmlNs)) {
                    nsManager.AddNamespace(attr.Prefix.Length == 0 ? string.Empty : attr.LocalName, attr.Value);
                }
            } 
            validator.ValidateElement(elementNode.LocalName, elementNode.NamespaceURI, schemaInfo, xsiType, xsiNil, null, null);
            ValidateAttributes(elementNode); 
            validator.ValidateEndOfAttributes(schemaInfo); 

            //If element has children, drill down 
            for (XmlNode child = elementNode.FirstChild; child != null; child = child.NextSibling) {
                ValidateNode(child);
            }
            //Validate end of element 
            currentNode = elementNode; //Reset current Node for validation call back
            validator.ValidateEndElement(schemaInfo); 
            //Get XmlName, as memberType / validity might be set now 
            if (psviAugmentation) {
                elementNode.XmlName = document.AddXmlName(elementNode.Prefix, elementNode.LocalName, elementNode.NamespaceURI, schemaInfo); 
                if (schemaInfo.IsDefault) { //the element has a default value
                    XmlText textNode = document.CreateTextNode(schemaInfo.SchemaElement.ElementDecl.DefaultValueRaw);
                    elementNode.AppendChild(textNode);
                } 
            }
 
            nsManager.PopScope(); //Pop current namespace scope 
        }
 
        private void ValidateAttributes(XmlElement elementNode) {
            XmlAttributeCollection attributes = elementNode.Attributes;
            XmlAttribute attr = null;
 
            for (int i = 0; i < attributes.Count; i++) {
                attr = attributes[i]; 
                currentNode = attr; //For nodeValueGetter to pick up the right attribute value 
                if (Ref.Equal(attr.NamespaceURI,NsXmlNs)) { //Do not validate namespace decls
                    continue; 
                }
                validator.ValidateAttribute(attr.LocalName, attr.NamespaceURI, nodeValueGetter, attributeSchemaInfo);
                if (psviAugmentation) {
                    attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo); 
                }
            } 
 
            if (psviAugmentation) {
                //Add default attributes to the attributes collection 
                if (defaultAttributes == null) {
                    defaultAttributes = new ArrayList();
                }
                else { 
                    defaultAttributes.Clear();
                } 
                validator.GetUnspecifiedDefaultAttributes(defaultAttributes); 
                XmlSchemaAttribute schemaAttribute = null;
                XmlQualifiedName attrQName; 
                attr = null;
                for (int i = 0; i < defaultAttributes.Count; i++) {
                    schemaAttribute = defaultAttributes[i] as XmlSchemaAttribute;
                    attrQName = schemaAttribute.QualifiedName; 
                    Debug.Assert(schemaAttribute != null);
                    attr = document.CreateDefaultAttribute(GetDefaultPrefix(attrQName.Namespace), attrQName.Name, attrQName.Namespace); 
                    SetDefaultAttributeSchemaInfo(schemaAttribute); 
                    attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo);
                    attr.AppendChild(document.CreateTextNode(schemaAttribute.AttDef.DefaultValueRaw)); 
                    attributes.Append(attr);
                    XmlUnspecifiedAttribute defAttr = attr as XmlUnspecifiedAttribute;
                    if (defAttr != null) {
                        defAttr.SetSpecified(false); 
                    }
                } 
            } 
        }
 
        private void SetDefaultAttributeSchemaInfo(XmlSchemaAttribute schemaAttribute) {
            Debug.Assert(attributeSchemaInfo != null);
            attributeSchemaInfo.Clear();
            attributeSchemaInfo.IsDefault = true; 
            attributeSchemaInfo.IsNil = false;
            attributeSchemaInfo.SchemaType = schemaAttribute.AttributeSchemaType; 
            attributeSchemaInfo.SchemaAttribute = schemaAttribute; 

            //Get memberType for default attribute 
            SchemaAttDef attributeDef = schemaAttribute.AttDef;
            if (attributeDef.Datatype.Variety == XmlSchemaDatatypeVariety.Union) {
                XsdSimpleValue simpleValue = attributeDef.DefaultValueTyped as XsdSimpleValue;
                Debug.Assert(simpleValue != null); 
                attributeSchemaInfo.MemberType = simpleValue.XmlType;
            } 
            attributeSchemaInfo.Validity = XmlSchemaValidity.Valid; 
        }
 
        private string GetDefaultPrefix(string attributeNS) {
            IDictionary namespaceDecls = NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.All);
            string defaultPrefix = null;
            string defaultNS; 
            attributeNS = nameTable.Add(attributeNS); //atomize ns
 
            foreach (KeyValuePair pair in namespaceDecls) { 
                defaultNS = nameTable.Add(pair.Value);
                if (object.ReferenceEquals(defaultNS, attributeNS)) { 
                    defaultPrefix = pair.Key;
                    if (defaultPrefix.Length != 0) { //Locate first non-empty prefix
                        return defaultPrefix;
                    } 
                }
            } 
            return defaultPrefix; 
        }
 
        private object GetNodeValue() {
            return currentNode.Value;
        }
 
        //Code for finding type during partial validation
        private XmlSchemaObject FindSchemaInfo(XmlElement elementToValidate) { 
            isPartialTreeValid = true; 
            Debug.Assert(elementToValidate.ParentNode.NodeType != XmlNodeType.Document); //Handle if it is the documentElement seperately
 
            //Create nodelist to navigate down again
            XmlNode currentNode = elementToValidate;
            IXmlSchemaInfo parentSchemaInfo = null;
            int nodeIndex = 0; 

            //Check common case of parent node first 
            XmlNode parentNode = currentNode.ParentNode; 
            do {
                parentSchemaInfo = parentNode.SchemaInfo; 
                if (parentSchemaInfo.SchemaElement != null || parentSchemaInfo.SchemaType != null) {
                    break; //Found ancestor with schemaInfo
                }
                CheckNodeSequenceCapacity(nodeIndex); 
                nodeSequenceToValidate[nodeIndex++] = parentNode;
                parentNode = parentNode.ParentNode; 
            } while (parentNode != null); 

            if (parentNode == null) { //Did not find any type info all the way to the root, currentNode is Document || DocumentFragment 
                nodeIndex = nodeIndex - 1; //Subtract the one for document and set the node to null
                nodeSequenceToValidate[nodeIndex] = null;
                return GetTypeFromAncestors(elementToValidate, null, nodeIndex);
            } 
            else {
                //Start validating down from the parent or ancestor that has schema info and shallow validate all previous siblings 
                //to correctly ascertain particle for current node 
                CheckNodeSequenceCapacity(nodeIndex);
                nodeSequenceToValidate[nodeIndex++] = parentNode; 
                XmlSchemaObject ancestorSchemaObject = parentSchemaInfo.SchemaElement;
                if (ancestorSchemaObject == null) {
                    ancestorSchemaObject = parentSchemaInfo.SchemaType;
                } 
                return GetTypeFromAncestors(elementToValidate, ancestorSchemaObject, nodeIndex);
 
            } 
        }
 
        /*private XmlSchemaElement GetTypeFromParent(XmlElement elementToValidate, XmlSchemaComplexType parentSchemaType) {
            XmlQualifiedName elementName = new XmlQualifiedName(elementToValidate.LocalName, elementToValidate.NamespaceURI);
            XmlSchemaElement elem = parentSchemaType.LocalElements[elementName] as XmlSchemaElement;
            if (elem == null) { //Element not found as direct child of the content model. It might be invalid at this position or it might be a substitution member 
                SchemaInfo compiledSchemaInfo = schemas.CompiledInfo;
                XmlSchemaElement memberElem = compiledSchemaInfo.GetElement(elementName); 
                if (memberElem != null) { 
                }
            } 
        }*/

        private void CheckNodeSequenceCapacity(int currentIndex) {
            if (nodeSequenceToValidate == null) { //Normally users would call Validate one level down, this allows for 4 
                nodeSequenceToValidate = new XmlNode[4];
            } 
            else if (currentIndex >= nodeSequenceToValidate.Length -1 ) { //reached capacity of array, Need to increase capacity to twice the initial 
                XmlNode[] newNodeSequence = new XmlNode[nodeSequenceToValidate.Length * 2];
                Array.Copy(nodeSequenceToValidate, 0, newNodeSequence, 0, nodeSequenceToValidate.Length); 
                nodeSequenceToValidate = newNodeSequence;
            }
        }
 
        private XmlSchemaAttribute FindSchemaInfo(XmlAttribute attributeToValidate) {
            XmlElement parentElement = attributeToValidate.OwnerElement; 
            XmlSchemaObject schemaObject = FindSchemaInfo(parentElement); 
            XmlSchemaComplexType elementSchemaType = GetComplexType(schemaObject);
            if (elementSchemaType == null) { 
                return null;
            }
            XmlQualifiedName attName = new XmlQualifiedName(attributeToValidate.LocalName, attributeToValidate.NamespaceURI);
            XmlSchemaAttribute schemaAttribute = elementSchemaType.AttributeUses[attName] as XmlSchemaAttribute; 
            if (schemaAttribute == null) {
                XmlSchemaAnyAttribute anyAttribute = elementSchemaType.AttributeWildcard; 
                if (anyAttribute != null) { 
                    if (anyAttribute.NamespaceList.Allows(attName)){ //Match wildcard against global attribute
                        schemaAttribute = schemas.GlobalAttributes[attName] as XmlSchemaAttribute; 
                    }
                }
            }
            return schemaAttribute; 
        }
 
        private XmlSchemaObject GetTypeFromAncestors(XmlElement elementToValidate, XmlSchemaObject ancestorType, int ancestorsCount) { 

            //schemaInfo is currentNode's schemaInfo 
            validator = CreateTypeFinderValidator(ancestorType);
            schemaInfo = new XmlSchemaInfo();

            //start at the ancestor to start validating 
            int startIndex = ancestorsCount - 1;
 
            bool ancestorHasWildCard = AncestorTypeHasWildcard(ancestorType); 
            for (int i = startIndex; i >= 0; i--) {
                XmlNode node = nodeSequenceToValidate[i]; 
                XmlElement currentElement = node as XmlElement;
                ValidateSingleElement(currentElement, false, schemaInfo);
                if (!ancestorHasWildCard) { //store type if ancestor does not have wildcard in its content model
                    currentElement.XmlName = document.AddXmlName(currentElement.Prefix, currentElement.LocalName, currentElement.NamespaceURI, schemaInfo); 
                    //update wildcard flag
                    ancestorHasWildCard = AncestorTypeHasWildcard(schemaInfo.SchemaElement); 
                } 

                validator.ValidateEndOfAttributes(null); 
                if (i > 0) {
                    ValidateChildrenTillNextAncestor(node, nodeSequenceToValidate[i - 1]);
                }
                else { //i == 0 
                    ValidateChildrenTillNextAncestor(node, elementToValidate);
                } 
            } 

            Debug.Assert(nodeSequenceToValidate[0] == elementToValidate.ParentNode); 
            //validate element whose type is needed,
            ValidateSingleElement(elementToValidate, false, schemaInfo);

            XmlSchemaObject schemaInfoFound = null; 
            if (schemaInfo.SchemaElement != null) {
                schemaInfoFound = schemaInfo.SchemaElement; 
            } 
            else {
                schemaInfoFound = schemaInfo.SchemaType; 
            }
            if (schemaInfoFound == null) { //Detect if the node was validated lax or skip
                if (validator.CurrentProcessContents == XmlSchemaContentProcessing.Skip) {
                    if (isPartialTreeValid) { //Then node assessed as skip; if there was error we turn processContents to skip as well. But this is not the same as validating as skip. 
                        return XmlSchemaComplexType.AnyTypeSkip;
                    } 
                } 
                else if (validator.CurrentProcessContents == XmlSchemaContentProcessing.Lax) {
                    return XmlSchemaComplexType.AnyType; 
                }
            }
            return schemaInfoFound;
        } 

        private bool AncestorTypeHasWildcard(XmlSchemaObject ancestorType) { 
            XmlSchemaComplexType ancestorSchemaType = GetComplexType(ancestorType); 
            if (ancestorType != null) {
                return ancestorSchemaType.HasWildCard; 
            }
            return false;
        }
 
        private XmlSchemaComplexType GetComplexType(XmlSchemaObject schemaObject) {
            if (schemaObject == null) { 
                return null; 
            }
            XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement; 
            XmlSchemaComplexType complexType = null;
            if (schemaElement != null) {
                complexType = schemaElement.ElementSchemaType as XmlSchemaComplexType;
            } 
            else {
                complexType = schemaObject as XmlSchemaComplexType; 
            } 
            return complexType;
        } 

        // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
        // Since the resource names passed to ValidateElement method are null and the function does not expose any resources
        // it is fine to supress the warning. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)] 
        private void ValidateSingleElement(XmlElement elementNode, bool skipToEnd, XmlSchemaInfo newSchemaInfo) { 
            nsManager.PushScope();
            Debug.Assert(elementNode != null); 

            XmlAttributeCollection attributes = elementNode.Attributes;
            XmlAttribute attr = null;
 
            //Find Xsi attributes that need to be processed before validating the element
            string xsiNil = null; 
            string xsiType = null; 

            for (int i = 0; i < attributes.Count; i++) { 
                attr = attributes[i];
                string objectNs = attr.NamespaceURI;
                string objectName = attr.LocalName;
                Debug.Assert(nameTable.Get(attr.NamespaceURI) != null); 
                Debug.Assert(nameTable.Get(attr.LocalName) != null);
 
                if (Ref.Equal(objectNs, NsXsi)) { 
                    if (Ref.Equal(objectName, XsiType)) {
                        xsiType = attr.Value; 
                    }
                    else if (Ref.Equal(objectName, XsiNil)) {
                        xsiNil = attr.Value;
                    } 
                }
                else if (Ref.Equal(objectNs,NsXmlNs)) { 
                    nsManager.AddNamespace(attr.Prefix.Length == 0 ? string.Empty : attr.LocalName, attr.Value); 
                }
            } 
            validator.ValidateElement(elementNode.LocalName, elementNode.NamespaceURI, newSchemaInfo, xsiType, xsiNil, null, null);
            //Validate end of element
            if (skipToEnd) {
                validator.ValidateEndOfAttributes(newSchemaInfo); 
                validator.SkipToEndElement(newSchemaInfo);
                nsManager.PopScope(); //Pop current namespace scope 
            } 
        }
 
        private void ValidateChildrenTillNextAncestor(XmlNode parentNode, XmlNode childToStopAt) {
            XmlNode child;

            for (child = parentNode.FirstChild; child != null; child = child.NextSibling) { 
                if (child == childToStopAt) {
                    break; 
                } 
                switch (child.NodeType) {
                    case XmlNodeType.EntityReference: 
                        ValidateChildrenTillNextAncestor(child, childToStopAt);
                        break;

                    case XmlNodeType.Element: //Flat validation, do not drill down into children 
                        ValidateSingleElement(child as XmlElement, true, null);
                        break; 
 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                        validator.ValidateText(child.Value);
                        break;

                    case XmlNodeType.Whitespace: 
                    case XmlNodeType.SignificantWhitespace:
                        validator.ValidateWhitespace(child.Value); 
                        break; 

                    case XmlNodeType.Comment: 
                    case XmlNodeType.ProcessingInstruction:
                        break;

                    default: 
                        throw new InvalidOperationException( Res.GetString( Res.Xml_UnexpectedNodeType, new string[]{ currentNode.NodeType.ToString() } ) );
                } 
            } 
            Debug.Assert(child == childToStopAt);
        } 

        private XmlSchemaValidator CreateTypeFinderValidator(XmlSchemaObject partialValidationType) {
            XmlSchemaValidator findTypeValidator = new XmlSchemaValidator(document.NameTable, document.Schemas, this.nsManager, XmlSchemaValidationFlags.None);
            findTypeValidator.ValidationEventHandler += new ValidationEventHandler(TypeFinderCallBack); 
            if (partialValidationType != null) {
                findTypeValidator.Initialize(partialValidationType); 
            } 
            else { //If we walked up to the root and no schemaInfo was there, start validating from root
                findTypeValidator.Initialize(); 
            }
            return findTypeValidator;
        }
 
        private void TypeFinderCallBack(object sender, ValidationEventArgs arg) {
            if (arg.Severity == XmlSeverityType.Error) { 
                isPartialTreeValid = false; 
            }
        } 

        private void InternalValidationCallBack(object sender, ValidationEventArgs arg) {
            if (arg.Severity == XmlSeverityType.Error) {
                isValid = false; 
            }
            XmlSchemaValidationException ex = arg.Exception as XmlSchemaValidationException; 
            Debug.Assert(ex != null); 
            ex.SetSourceObject(currentNode);
            if (this.eventHandler != null) { //Invoke user's event handler 
                eventHandler(sender, arg);
            }
            else if (arg.Severity == XmlSeverityType.Error) {
                throw ex; 
            }
        } 
 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Text;
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Xml.Schema; 
using System.Xml.XPath;
using System.Globalization; 
using System.Security; 
using System.Security.Policy;
using System.Security.Permissions; 
using System.Reflection;
using System.Runtime.Versioning;

namespace System.Xml { 

    internal sealed class DocumentSchemaValidator : IXmlNamespaceResolver { 
        XmlSchemaValidator validator; 
        XmlSchemaSet schemas;
 
        XmlNamespaceManager nsManager;
        XmlNameTable nameTable;

        //Attributes 
        ArrayList defaultAttributes;
        XmlValueGetter nodeValueGetter; 
        XmlSchemaInfo attributeSchemaInfo; 

        //Element PSVI 
        XmlSchemaInfo schemaInfo;

        //Event Handler
        ValidationEventHandler eventHandler; 
        ValidationEventHandler internalEventHandler;
 
        //Store nodes 
        XmlNode startNode;
        XmlNode currentNode; 
        XmlDocument document;

        //List of nodes for partial validation tree walk
        XmlNode[] nodeSequenceToValidate; 
        bool isPartialTreeValid;
 
        bool psviAugmentation; 
        bool isValid;
 
        //To avoid SchemaNames creation
        private string NsXmlNs;
        private string NsXsi;
        private string XsiType; 
        private string XsiNil;
 
        public DocumentSchemaValidator(XmlDocument ownerDocument, XmlSchemaSet schemas, ValidationEventHandler eventHandler) { 
            this.schemas = schemas;
            this.eventHandler = eventHandler; 
            document = ownerDocument;
            this.internalEventHandler = new ValidationEventHandler(InternalValidationCallBack);

            this.nameTable = document.NameTable; 
            nsManager = new XmlNamespaceManager(nameTable);
 
            Debug.Assert(schemas != null && schemas.Count > 0); 

            nodeValueGetter = new XmlValueGetter(GetNodeValue); 
            psviAugmentation = true;

            //Add common strings to be compared to NameTable
            NsXmlNs = nameTable.Add(XmlReservedNs.NsXmlNs); 
            NsXsi = nameTable.Add(XmlReservedNs.NsXsi);
            XsiType = nameTable.Add("type"); 
            XsiNil = nameTable.Add("nil"); 
        }
 
        public bool PsviAugmentation {
            get { return psviAugmentation; }
            set { psviAugmentation = value; }
        } 

        public bool Validate(XmlNode nodeToValidate) { 
            XmlSchemaObject partialValidationType = null; 
            XmlSchemaValidationFlags validationFlags = XmlSchemaValidationFlags.AllowXmlAttributes;
            Debug.Assert(nodeToValidate.SchemaInfo != null); 

            startNode = nodeToValidate;
            switch (nodeToValidate.NodeType) {
                case XmlNodeType.Document: 
                    validationFlags |= XmlSchemaValidationFlags.ProcessIdentityConstraints;
                    break; 
 
                case XmlNodeType.DocumentFragment:
                    break; 

                case XmlNodeType.Element: //Validate children of this element
                    IXmlSchemaInfo schemaInfo = nodeToValidate.SchemaInfo;
                    XmlSchemaElement schemaElement = schemaInfo.SchemaElement; 
                    if (schemaElement != null) {
                        if (!schemaElement.RefName.IsEmpty) { //If it is element ref, 
                            partialValidationType = schemas.GlobalElements[schemaElement.QualifiedName]; //Get Global element with correct Nillable, Default etc 
                        }
                        else { //local element 
                            partialValidationType = schemaElement;
                        }
                        //Verify that if there was xsi:type, the schemaElement returned has the correct type set
                        Debug.Assert(schemaElement.ElementSchemaType == schemaInfo.SchemaType); 
                    }
                    else { //Can be an element that matched xs:any and had xsi:type 
                        partialValidationType = schemaInfo.SchemaType; 

                        if (partialValidationType == null) { //Validated against xs:any with pc= lax or skip or undeclared / not validated element 
                            if (nodeToValidate.ParentNode.NodeType == XmlNodeType.Document) {
                                //If this is the documentElement and it has not been validated at all
                                nodeToValidate = nodeToValidate.ParentNode;
                            } 
                            else {
                                partialValidationType = FindSchemaInfo(nodeToValidate as XmlElement); 
                                if (partialValidationType == null) { 
                                    throw new XmlSchemaValidationException(Res.XmlDocument_NoNodeSchemaInfo, null, nodeToValidate);
                                } 
                            }
                        }
                    }
                    break; 

                case XmlNodeType.Attribute: 
                    if (nodeToValidate.XPNodeType == XPathNodeType.Namespace) goto default; 
                    partialValidationType = nodeToValidate.SchemaInfo.SchemaAttribute;
                    if (partialValidationType == null) { //Validated against xs:anyAttribute with pc = lax or skip / undeclared attribute 
                        partialValidationType = FindSchemaInfo(nodeToValidate as XmlAttribute);
                        if (partialValidationType == null) {
                            throw new XmlSchemaValidationException(Res.XmlDocument_NoNodeSchemaInfo, null, nodeToValidate);
                        } 
                    }
                    break; 
 
                default:
                    throw new InvalidOperationException(Res.GetString(Res.XmlDocument_ValidateInvalidNodeType, null)); 
            }
            isValid = true;
            CreateValidator(partialValidationType, validationFlags);
            if (psviAugmentation) { 
                if (schemaInfo == null) { //Might have created it during FindSchemaInfo
                    schemaInfo = new XmlSchemaInfo(); 
                } 
                attributeSchemaInfo = new XmlSchemaInfo();
            } 
            ValidateNode(nodeToValidate);
            validator.EndValidation();
            return isValid;
        } 

        public IDictionary GetNamespacesInScope(XmlNamespaceScope scope) { 
            IDictionary dictionary = nsManager.GetNamespacesInScope(scope); 
            if (scope != XmlNamespaceScope.Local) {
                XmlNode node = startNode; 
                while (node != null) {
                    switch (node.NodeType) {
                        case XmlNodeType.Element:
                            XmlElement elem = (XmlElement)node; 
                            if (elem.HasAttributes) {
                                XmlAttributeCollection attrs = elem.Attributes; 
                                for (int i = 0; i < attrs.Count; i++) { 
                                    XmlAttribute attr = attrs[i];
                                    if (Ref.Equal(attr.NamespaceURI, document.strReservedXmlns)) { 
                                        if (attr.Prefix.Length == 0) {
                                            // xmlns='' declaration
                                            if (!dictionary.ContainsKey(string.Empty)) {
                                                dictionary.Add(string.Empty, attr.Value); 
                                            }
                                        } 
                                        else { 
                                            // xmlns:prefix='' declaration
                                            if (!dictionary.ContainsKey(attr.LocalName)) { 
                                                dictionary.Add(attr.LocalName, attr.Value);
                                            }
                                        }
                                    } 
                                }
                            } 
                            node = node.ParentNode; 
                            break;
                        case XmlNodeType.Attribute: 
                            node = ((XmlAttribute)node).OwnerElement;
                            break;
                        default:
                            node = node.ParentNode; 
                            break;
                    } 
                } 
            }
            return dictionary; 
        }

        public string LookupNamespace(string prefix) {
            string namespaceName = nsManager.LookupNamespace(prefix); 
            if (namespaceName == null) {
                namespaceName = startNode.GetNamespaceOfPrefixStrict(prefix); 
            } 
            return namespaceName;
        } 

        public string LookupPrefix(string namespaceName) {
            string prefix = nsManager.LookupPrefix(namespaceName);
            if (prefix == null) { 
                prefix = startNode.GetPrefixOfNamespaceStrict(namespaceName);
            } 
            return prefix; 
        }
 
        private IXmlNamespaceResolver NamespaceResolver {
            get {
                if ((object)startNode == (object)document) {
                    return nsManager; 
                }
                return this; 
            } 
        }
 
        private void CreateValidator(XmlSchemaObject partialValidationType, XmlSchemaValidationFlags validationFlags) {
            validator = new XmlSchemaValidator(nameTable, schemas, NamespaceResolver, validationFlags);
            validator.SourceUri = XmlConvert.ToUri(document.BaseURI);
            validator.XmlResolver = null; 
            validator.ValidationEventHandler += internalEventHandler;
            validator.ValidationEventSender = this; 
 
            if (partialValidationType != null) {
                validator.Initialize(partialValidationType); 
            }
            else {
                validator.Initialize();
            } 
        }
 
        private void ValidateNode(XmlNode node) { 
            currentNode = node;
            switch (currentNode.NodeType) { 
                case XmlNodeType.Document:
                    XmlElement docElem = ((XmlDocument)node).DocumentElement;
                    if (docElem == null) {
                        throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidXmlDocument, Res.GetString(Res.Xdom_NoRootEle))); 
                    }
                    ValidateNode(docElem); 
                    break; 

                case XmlNodeType.DocumentFragment: 
                case XmlNodeType.EntityReference:
                    for (XmlNode child = node.FirstChild; child != null; child = child.NextSibling) {
                        ValidateNode(child);
                    } 
                    break;
 
                case XmlNodeType.Element: 
                    ValidateElement();
                    break; 

                case XmlNodeType.Attribute: //Top-level attribute
                    XmlAttribute attr = currentNode as XmlAttribute;
                    validator.ValidateAttribute(attr.LocalName, attr.NamespaceURI, nodeValueGetter, attributeSchemaInfo); 
                    if (psviAugmentation) {
                        attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo); 
                    } 
                    break;
 
                case XmlNodeType.Text:
                    validator.ValidateText(nodeValueGetter);
                    break;
 
                case XmlNodeType.CDATA:
                    validator.ValidateText(nodeValueGetter); 
                    break; 

                case XmlNodeType.Whitespace: 
                case XmlNodeType.SignificantWhitespace:
                    validator.ValidateWhitespace(nodeValueGetter);
                    break;
 
                case XmlNodeType.Comment:
                case XmlNodeType.ProcessingInstruction: 
                    break; 

                default: 
                    throw new InvalidOperationException( Res.GetString( Res.Xml_UnexpectedNodeType, new string[]{ currentNode.NodeType.ToString() } ) );
            }
        }
 
        // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
        // Since the resource names passed to ValidateElement method are null and the function does not expose any resources 
        // it is fine to suppress the SxS warning. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)] 
        private void ValidateElement() {
            nsManager.PushScope();
            XmlElement elementNode = currentNode as XmlElement;
            Debug.Assert(elementNode != null); 

            XmlAttributeCollection attributes = elementNode.Attributes; 
            XmlAttribute attr = null; 

            //Find Xsi attributes that need to be processed before validating the element 
            string xsiNil = null;
            string xsiType = null;

            for (int i = 0; i < attributes.Count; i++) { 
                attr = attributes[i];
                string objectNs = attr.NamespaceURI; 
                string objectName = attr.LocalName; 
                Debug.Assert(nameTable.Get(attr.NamespaceURI) != null);
                Debug.Assert(nameTable.Get(attr.LocalName) != null); 

                if (Ref.Equal(objectNs, NsXsi)) {
                    if (Ref.Equal(objectName, XsiType)) {
                        xsiType = attr.Value; 
                    }
                    else if (Ref.Equal(objectName, XsiNil)) { 
                        xsiNil = attr.Value; 
                    }
                } 
                else if (Ref.Equal(objectNs,NsXmlNs)) {
                    nsManager.AddNamespace(attr.Prefix.Length == 0 ? string.Empty : attr.LocalName, attr.Value);
                }
            } 
            validator.ValidateElement(elementNode.LocalName, elementNode.NamespaceURI, schemaInfo, xsiType, xsiNil, null, null);
            ValidateAttributes(elementNode); 
            validator.ValidateEndOfAttributes(schemaInfo); 

            //If element has children, drill down 
            for (XmlNode child = elementNode.FirstChild; child != null; child = child.NextSibling) {
                ValidateNode(child);
            }
            //Validate end of element 
            currentNode = elementNode; //Reset current Node for validation call back
            validator.ValidateEndElement(schemaInfo); 
            //Get XmlName, as memberType / validity might be set now 
            if (psviAugmentation) {
                elementNode.XmlName = document.AddXmlName(elementNode.Prefix, elementNode.LocalName, elementNode.NamespaceURI, schemaInfo); 
                if (schemaInfo.IsDefault) { //the element has a default value
                    XmlText textNode = document.CreateTextNode(schemaInfo.SchemaElement.ElementDecl.DefaultValueRaw);
                    elementNode.AppendChild(textNode);
                } 
            }
 
            nsManager.PopScope(); //Pop current namespace scope 
        }
 
        private void ValidateAttributes(XmlElement elementNode) {
            XmlAttributeCollection attributes = elementNode.Attributes;
            XmlAttribute attr = null;
 
            for (int i = 0; i < attributes.Count; i++) {
                attr = attributes[i]; 
                currentNode = attr; //For nodeValueGetter to pick up the right attribute value 
                if (Ref.Equal(attr.NamespaceURI,NsXmlNs)) { //Do not validate namespace decls
                    continue; 
                }
                validator.ValidateAttribute(attr.LocalName, attr.NamespaceURI, nodeValueGetter, attributeSchemaInfo);
                if (psviAugmentation) {
                    attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo); 
                }
            } 
 
            if (psviAugmentation) {
                //Add default attributes to the attributes collection 
                if (defaultAttributes == null) {
                    defaultAttributes = new ArrayList();
                }
                else { 
                    defaultAttributes.Clear();
                } 
                validator.GetUnspecifiedDefaultAttributes(defaultAttributes); 
                XmlSchemaAttribute schemaAttribute = null;
                XmlQualifiedName attrQName; 
                attr = null;
                for (int i = 0; i < defaultAttributes.Count; i++) {
                    schemaAttribute = defaultAttributes[i] as XmlSchemaAttribute;
                    attrQName = schemaAttribute.QualifiedName; 
                    Debug.Assert(schemaAttribute != null);
                    attr = document.CreateDefaultAttribute(GetDefaultPrefix(attrQName.Namespace), attrQName.Name, attrQName.Namespace); 
                    SetDefaultAttributeSchemaInfo(schemaAttribute); 
                    attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo);
                    attr.AppendChild(document.CreateTextNode(schemaAttribute.AttDef.DefaultValueRaw)); 
                    attributes.Append(attr);
                    XmlUnspecifiedAttribute defAttr = attr as XmlUnspecifiedAttribute;
                    if (defAttr != null) {
                        defAttr.SetSpecified(false); 
                    }
                } 
            } 
        }
 
        private void SetDefaultAttributeSchemaInfo(XmlSchemaAttribute schemaAttribute) {
            Debug.Assert(attributeSchemaInfo != null);
            attributeSchemaInfo.Clear();
            attributeSchemaInfo.IsDefault = true; 
            attributeSchemaInfo.IsNil = false;
            attributeSchemaInfo.SchemaType = schemaAttribute.AttributeSchemaType; 
            attributeSchemaInfo.SchemaAttribute = schemaAttribute; 

            //Get memberType for default attribute 
            SchemaAttDef attributeDef = schemaAttribute.AttDef;
            if (attributeDef.Datatype.Variety == XmlSchemaDatatypeVariety.Union) {
                XsdSimpleValue simpleValue = attributeDef.DefaultValueTyped as XsdSimpleValue;
                Debug.Assert(simpleValue != null); 
                attributeSchemaInfo.MemberType = simpleValue.XmlType;
            } 
            attributeSchemaInfo.Validity = XmlSchemaValidity.Valid; 
        }
 
        private string GetDefaultPrefix(string attributeNS) {
            IDictionary namespaceDecls = NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.All);
            string defaultPrefix = null;
            string defaultNS; 
            attributeNS = nameTable.Add(attributeNS); //atomize ns
 
            foreach (KeyValuePair pair in namespaceDecls) { 
                defaultNS = nameTable.Add(pair.Value);
                if (object.ReferenceEquals(defaultNS, attributeNS)) { 
                    defaultPrefix = pair.Key;
                    if (defaultPrefix.Length != 0) { //Locate first non-empty prefix
                        return defaultPrefix;
                    } 
                }
            } 
            return defaultPrefix; 
        }
 
        private object GetNodeValue() {
            return currentNode.Value;
        }
 
        //Code for finding type during partial validation
        private XmlSchemaObject FindSchemaInfo(XmlElement elementToValidate) { 
            isPartialTreeValid = true; 
            Debug.Assert(elementToValidate.ParentNode.NodeType != XmlNodeType.Document); //Handle if it is the documentElement seperately
 
            //Create nodelist to navigate down again
            XmlNode currentNode = elementToValidate;
            IXmlSchemaInfo parentSchemaInfo = null;
            int nodeIndex = 0; 

            //Check common case of parent node first 
            XmlNode parentNode = currentNode.ParentNode; 
            do {
                parentSchemaInfo = parentNode.SchemaInfo; 
                if (parentSchemaInfo.SchemaElement != null || parentSchemaInfo.SchemaType != null) {
                    break; //Found ancestor with schemaInfo
                }
                CheckNodeSequenceCapacity(nodeIndex); 
                nodeSequenceToValidate[nodeIndex++] = parentNode;
                parentNode = parentNode.ParentNode; 
            } while (parentNode != null); 

            if (parentNode == null) { //Did not find any type info all the way to the root, currentNode is Document || DocumentFragment 
                nodeIndex = nodeIndex - 1; //Subtract the one for document and set the node to null
                nodeSequenceToValidate[nodeIndex] = null;
                return GetTypeFromAncestors(elementToValidate, null, nodeIndex);
            } 
            else {
                //Start validating down from the parent or ancestor that has schema info and shallow validate all previous siblings 
                //to correctly ascertain particle for current node 
                CheckNodeSequenceCapacity(nodeIndex);
                nodeSequenceToValidate[nodeIndex++] = parentNode; 
                XmlSchemaObject ancestorSchemaObject = parentSchemaInfo.SchemaElement;
                if (ancestorSchemaObject == null) {
                    ancestorSchemaObject = parentSchemaInfo.SchemaType;
                } 
                return GetTypeFromAncestors(elementToValidate, ancestorSchemaObject, nodeIndex);
 
            } 
        }
 
        /*private XmlSchemaElement GetTypeFromParent(XmlElement elementToValidate, XmlSchemaComplexType parentSchemaType) {
            XmlQualifiedName elementName = new XmlQualifiedName(elementToValidate.LocalName, elementToValidate.NamespaceURI);
            XmlSchemaElement elem = parentSchemaType.LocalElements[elementName] as XmlSchemaElement;
            if (elem == null) { //Element not found as direct child of the content model. It might be invalid at this position or it might be a substitution member 
                SchemaInfo compiledSchemaInfo = schemas.CompiledInfo;
                XmlSchemaElement memberElem = compiledSchemaInfo.GetElement(elementName); 
                if (memberElem != null) { 
                }
            } 
        }*/

        private void CheckNodeSequenceCapacity(int currentIndex) {
            if (nodeSequenceToValidate == null) { //Normally users would call Validate one level down, this allows for 4 
                nodeSequenceToValidate = new XmlNode[4];
            } 
            else if (currentIndex >= nodeSequenceToValidate.Length -1 ) { //reached capacity of array, Need to increase capacity to twice the initial 
                XmlNode[] newNodeSequence = new XmlNode[nodeSequenceToValidate.Length * 2];
                Array.Copy(nodeSequenceToValidate, 0, newNodeSequence, 0, nodeSequenceToValidate.Length); 
                nodeSequenceToValidate = newNodeSequence;
            }
        }
 
        private XmlSchemaAttribute FindSchemaInfo(XmlAttribute attributeToValidate) {
            XmlElement parentElement = attributeToValidate.OwnerElement; 
            XmlSchemaObject schemaObject = FindSchemaInfo(parentElement); 
            XmlSchemaComplexType elementSchemaType = GetComplexType(schemaObject);
            if (elementSchemaType == null) { 
                return null;
            }
            XmlQualifiedName attName = new XmlQualifiedName(attributeToValidate.LocalName, attributeToValidate.NamespaceURI);
            XmlSchemaAttribute schemaAttribute = elementSchemaType.AttributeUses[attName] as XmlSchemaAttribute; 
            if (schemaAttribute == null) {
                XmlSchemaAnyAttribute anyAttribute = elementSchemaType.AttributeWildcard; 
                if (anyAttribute != null) { 
                    if (anyAttribute.NamespaceList.Allows(attName)){ //Match wildcard against global attribute
                        schemaAttribute = schemas.GlobalAttributes[attName] as XmlSchemaAttribute; 
                    }
                }
            }
            return schemaAttribute; 
        }
 
        private XmlSchemaObject GetTypeFromAncestors(XmlElement elementToValidate, XmlSchemaObject ancestorType, int ancestorsCount) { 

            //schemaInfo is currentNode's schemaInfo 
            validator = CreateTypeFinderValidator(ancestorType);
            schemaInfo = new XmlSchemaInfo();

            //start at the ancestor to start validating 
            int startIndex = ancestorsCount - 1;
 
            bool ancestorHasWildCard = AncestorTypeHasWildcard(ancestorType); 
            for (int i = startIndex; i >= 0; i--) {
                XmlNode node = nodeSequenceToValidate[i]; 
                XmlElement currentElement = node as XmlElement;
                ValidateSingleElement(currentElement, false, schemaInfo);
                if (!ancestorHasWildCard) { //store type if ancestor does not have wildcard in its content model
                    currentElement.XmlName = document.AddXmlName(currentElement.Prefix, currentElement.LocalName, currentElement.NamespaceURI, schemaInfo); 
                    //update wildcard flag
                    ancestorHasWildCard = AncestorTypeHasWildcard(schemaInfo.SchemaElement); 
                } 

                validator.ValidateEndOfAttributes(null); 
                if (i > 0) {
                    ValidateChildrenTillNextAncestor(node, nodeSequenceToValidate[i - 1]);
                }
                else { //i == 0 
                    ValidateChildrenTillNextAncestor(node, elementToValidate);
                } 
            } 

            Debug.Assert(nodeSequenceToValidate[0] == elementToValidate.ParentNode); 
            //validate element whose type is needed,
            ValidateSingleElement(elementToValidate, false, schemaInfo);

            XmlSchemaObject schemaInfoFound = null; 
            if (schemaInfo.SchemaElement != null) {
                schemaInfoFound = schemaInfo.SchemaElement; 
            } 
            else {
                schemaInfoFound = schemaInfo.SchemaType; 
            }
            if (schemaInfoFound == null) { //Detect if the node was validated lax or skip
                if (validator.CurrentProcessContents == XmlSchemaContentProcessing.Skip) {
                    if (isPartialTreeValid) { //Then node assessed as skip; if there was error we turn processContents to skip as well. But this is not the same as validating as skip. 
                        return XmlSchemaComplexType.AnyTypeSkip;
                    } 
                } 
                else if (validator.CurrentProcessContents == XmlSchemaContentProcessing.Lax) {
                    return XmlSchemaComplexType.AnyType; 
                }
            }
            return schemaInfoFound;
        } 

        private bool AncestorTypeHasWildcard(XmlSchemaObject ancestorType) { 
            XmlSchemaComplexType ancestorSchemaType = GetComplexType(ancestorType); 
            if (ancestorType != null) {
                return ancestorSchemaType.HasWildCard; 
            }
            return false;
        }
 
        private XmlSchemaComplexType GetComplexType(XmlSchemaObject schemaObject) {
            if (schemaObject == null) { 
                return null; 
            }
            XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement; 
            XmlSchemaComplexType complexType = null;
            if (schemaElement != null) {
                complexType = schemaElement.ElementSchemaType as XmlSchemaComplexType;
            } 
            else {
                complexType = schemaObject as XmlSchemaComplexType; 
            } 
            return complexType;
        } 

        // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
        // Since the resource names passed to ValidateElement method are null and the function does not expose any resources
        // it is fine to supress the warning. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)] 
        private void ValidateSingleElement(XmlElement elementNode, bool skipToEnd, XmlSchemaInfo newSchemaInfo) { 
            nsManager.PushScope();
            Debug.Assert(elementNode != null); 

            XmlAttributeCollection attributes = elementNode.Attributes;
            XmlAttribute attr = null;
 
            //Find Xsi attributes that need to be processed before validating the element
            string xsiNil = null; 
            string xsiType = null; 

            for (int i = 0; i < attributes.Count; i++) { 
                attr = attributes[i];
                string objectNs = attr.NamespaceURI;
                string objectName = attr.LocalName;
                Debug.Assert(nameTable.Get(attr.NamespaceURI) != null); 
                Debug.Assert(nameTable.Get(attr.LocalName) != null);
 
                if (Ref.Equal(objectNs, NsXsi)) { 
                    if (Ref.Equal(objectName, XsiType)) {
                        xsiType = attr.Value; 
                    }
                    else if (Ref.Equal(objectName, XsiNil)) {
                        xsiNil = attr.Value;
                    } 
                }
                else if (Ref.Equal(objectNs,NsXmlNs)) { 
                    nsManager.AddNamespace(attr.Prefix.Length == 0 ? string.Empty : attr.LocalName, attr.Value); 
                }
            } 
            validator.ValidateElement(elementNode.LocalName, elementNode.NamespaceURI, newSchemaInfo, xsiType, xsiNil, null, null);
            //Validate end of element
            if (skipToEnd) {
                validator.ValidateEndOfAttributes(newSchemaInfo); 
                validator.SkipToEndElement(newSchemaInfo);
                nsManager.PopScope(); //Pop current namespace scope 
            } 
        }
 
        private void ValidateChildrenTillNextAncestor(XmlNode parentNode, XmlNode childToStopAt) {
            XmlNode child;

            for (child = parentNode.FirstChild; child != null; child = child.NextSibling) { 
                if (child == childToStopAt) {
                    break; 
                } 
                switch (child.NodeType) {
                    case XmlNodeType.EntityReference: 
                        ValidateChildrenTillNextAncestor(child, childToStopAt);
                        break;

                    case XmlNodeType.Element: //Flat validation, do not drill down into children 
                        ValidateSingleElement(child as XmlElement, true, null);
                        break; 
 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                        validator.ValidateText(child.Value);
                        break;

                    case XmlNodeType.Whitespace: 
                    case XmlNodeType.SignificantWhitespace:
                        validator.ValidateWhitespace(child.Value); 
                        break; 

                    case XmlNodeType.Comment: 
                    case XmlNodeType.ProcessingInstruction:
                        break;

                    default: 
                        throw new InvalidOperationException( Res.GetString( Res.Xml_UnexpectedNodeType, new string[]{ currentNode.NodeType.ToString() } ) );
                } 
            } 
            Debug.Assert(child == childToStopAt);
        } 

        private XmlSchemaValidator CreateTypeFinderValidator(XmlSchemaObject partialValidationType) {
            XmlSchemaValidator findTypeValidator = new XmlSchemaValidator(document.NameTable, document.Schemas, this.nsManager, XmlSchemaValidationFlags.None);
            findTypeValidator.ValidationEventHandler += new ValidationEventHandler(TypeFinderCallBack); 
            if (partialValidationType != null) {
                findTypeValidator.Initialize(partialValidationType); 
            } 
            else { //If we walked up to the root and no schemaInfo was there, start validating from root
                findTypeValidator.Initialize(); 
            }
            return findTypeValidator;
        }
 
        private void TypeFinderCallBack(object sender, ValidationEventArgs arg) {
            if (arg.Severity == XmlSeverityType.Error) { 
                isPartialTreeValid = false; 
            }
        } 

        private void InternalValidationCallBack(object sender, ValidationEventArgs arg) {
            if (arg.Severity == XmlSeverityType.Error) {
                isValid = false; 
            }
            XmlSchemaValidationException ex = arg.Exception as XmlSchemaValidationException; 
            Debug.Assert(ex != null); 
            ex.SetSourceObject(currentNode);
            if (this.eventHandler != null) { //Invoke user's event handler 
                eventHandler(sender, arg);
            }
            else if (arg.Severity == XmlSeverityType.Error) {
                throw ex; 
            }
        } 
 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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