1 //------------------------------------------------------------------------------
2 // <copyright file="XmlDocumentValidator.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
10 using System.Collections;
11 using System.Collections.Generic;
12 using System.Diagnostics;
14 using System.Xml.Schema;
15 using System.Xml.XPath;
16 using System.Globalization;
17 using System.Security;
18 using System.Security.Policy;
19 using System.Security.Permissions;
20 using System.Reflection;
21 using System.Runtime.Versioning;
23 namespace System.Xml {
25 internal sealed class DocumentSchemaValidator : IXmlNamespaceResolver {
26 XmlSchemaValidator validator;
29 XmlNamespaceManager nsManager;
30 XmlNameTable nameTable;
33 ArrayList defaultAttributes;
34 XmlValueGetter nodeValueGetter;
35 XmlSchemaInfo attributeSchemaInfo;
38 XmlSchemaInfo schemaInfo;
41 ValidationEventHandler eventHandler;
42 ValidationEventHandler internalEventHandler;
49 //List of nodes for partial validation tree walk
50 XmlNode[] nodeSequenceToValidate;
51 bool isPartialTreeValid;
53 bool psviAugmentation;
56 //To avoid SchemaNames creation
57 private string NsXmlNs;
59 private string XsiType;
60 private string XsiNil;
62 public DocumentSchemaValidator(XmlDocument ownerDocument, XmlSchemaSet schemas, ValidationEventHandler eventHandler) {
63 this.schemas = schemas;
64 this.eventHandler = eventHandler;
65 document = ownerDocument;
66 this.internalEventHandler = new ValidationEventHandler(InternalValidationCallBack);
68 this.nameTable = document.NameTable;
69 nsManager = new XmlNamespaceManager(nameTable);
71 Debug.Assert(schemas != null && schemas.Count > 0);
73 nodeValueGetter = new XmlValueGetter(GetNodeValue);
74 psviAugmentation = true;
76 //Add common strings to be compared to NameTable
77 NsXmlNs = nameTable.Add(XmlReservedNs.NsXmlNs);
78 NsXsi = nameTable.Add(XmlReservedNs.NsXsi);
79 XsiType = nameTable.Add("type");
80 XsiNil = nameTable.Add("nil");
83 public bool PsviAugmentation {
84 get { return psviAugmentation; }
85 set { psviAugmentation = value; }
88 public bool Validate(XmlNode nodeToValidate) {
89 XmlSchemaObject partialValidationType = null;
90 XmlSchemaValidationFlags validationFlags = XmlSchemaValidationFlags.AllowXmlAttributes;
91 Debug.Assert(nodeToValidate.SchemaInfo != null);
93 startNode = nodeToValidate;
94 switch (nodeToValidate.NodeType) {
95 case XmlNodeType.Document:
96 validationFlags |= XmlSchemaValidationFlags.ProcessIdentityConstraints;
99 case XmlNodeType.DocumentFragment:
102 case XmlNodeType.Element: //Validate children of this element
103 IXmlSchemaInfo schemaInfo = nodeToValidate.SchemaInfo;
104 XmlSchemaElement schemaElement = schemaInfo.SchemaElement;
105 if (schemaElement != null) {
106 if (!schemaElement.RefName.IsEmpty) { //If it is element ref,
107 partialValidationType = schemas.GlobalElements[schemaElement.QualifiedName]; //Get Global element with correct Nillable, Default etc
109 else { //local element
110 partialValidationType = schemaElement;
112 //Verify that if there was xsi:type, the schemaElement returned has the correct type set
113 Debug.Assert(schemaElement.ElementSchemaType == schemaInfo.SchemaType);
115 else { //Can be an element that matched xs:any and had xsi:type
116 partialValidationType = schemaInfo.SchemaType;
118 if (partialValidationType == null) { //Validated against xs:any with pc= lax or skip or undeclared / not validated element
119 if (nodeToValidate.ParentNode.NodeType == XmlNodeType.Document) {
120 //If this is the documentElement and it has not been validated at all
121 nodeToValidate = nodeToValidate.ParentNode;
124 partialValidationType = FindSchemaInfo(nodeToValidate as XmlElement);
125 if (partialValidationType == null) {
126 throw new XmlSchemaValidationException(Res.XmlDocument_NoNodeSchemaInfo, null, nodeToValidate);
133 case XmlNodeType.Attribute:
134 if (nodeToValidate.XPNodeType == XPathNodeType.Namespace) goto default;
135 partialValidationType = nodeToValidate.SchemaInfo.SchemaAttribute;
136 if (partialValidationType == null) { //Validated against xs:anyAttribute with pc = lax or skip / undeclared attribute
137 partialValidationType = FindSchemaInfo(nodeToValidate as XmlAttribute);
138 if (partialValidationType == null) {
139 throw new XmlSchemaValidationException(Res.XmlDocument_NoNodeSchemaInfo, null, nodeToValidate);
145 throw new InvalidOperationException(Res.GetString(Res.XmlDocument_ValidateInvalidNodeType, null));
148 CreateValidator(partialValidationType, validationFlags);
149 if (psviAugmentation) {
150 if (schemaInfo == null) { //Might have created it during FindSchemaInfo
151 schemaInfo = new XmlSchemaInfo();
153 attributeSchemaInfo = new XmlSchemaInfo();
155 ValidateNode(nodeToValidate);
156 validator.EndValidation();
160 public IDictionary<string,string> GetNamespacesInScope(XmlNamespaceScope scope) {
161 IDictionary<string,string> dictionary = nsManager.GetNamespacesInScope(scope);
162 if (scope != XmlNamespaceScope.Local) {
163 XmlNode node = startNode;
164 while (node != null) {
165 switch (node.NodeType) {
166 case XmlNodeType.Element:
167 XmlElement elem = (XmlElement)node;
168 if (elem.HasAttributes) {
169 XmlAttributeCollection attrs = elem.Attributes;
170 for (int i = 0; i < attrs.Count; i++) {
171 XmlAttribute attr = attrs[i];
172 if (Ref.Equal(attr.NamespaceURI, document.strReservedXmlns)) {
173 if (attr.Prefix.Length == 0) {
174 // xmlns='' declaration
175 if (!dictionary.ContainsKey(string.Empty)) {
176 dictionary.Add(string.Empty, attr.Value);
180 // xmlns:prefix='' declaration
181 if (!dictionary.ContainsKey(attr.LocalName)) {
182 dictionary.Add(attr.LocalName, attr.Value);
188 node = node.ParentNode;
190 case XmlNodeType.Attribute:
191 node = ((XmlAttribute)node).OwnerElement;
194 node = node.ParentNode;
202 public string LookupNamespace(string prefix) {
203 string namespaceName = nsManager.LookupNamespace(prefix);
204 if (namespaceName == null) {
205 namespaceName = startNode.GetNamespaceOfPrefixStrict(prefix);
207 return namespaceName;
210 public string LookupPrefix(string namespaceName) {
211 string prefix = nsManager.LookupPrefix(namespaceName);
212 if (prefix == null) {
213 prefix = startNode.GetPrefixOfNamespaceStrict(namespaceName);
218 private IXmlNamespaceResolver NamespaceResolver {
220 if ((object)startNode == (object)document) {
227 private void CreateValidator(XmlSchemaObject partialValidationType, XmlSchemaValidationFlags validationFlags) {
228 validator = new XmlSchemaValidator(nameTable, schemas, NamespaceResolver, validationFlags);
229 validator.SourceUri = XmlConvert.ToUri(document.BaseURI);
230 validator.XmlResolver = null;
231 validator.ValidationEventHandler += internalEventHandler;
232 validator.ValidationEventSender = this;
234 if (partialValidationType != null) {
235 validator.Initialize(partialValidationType);
238 validator.Initialize();
242 private void ValidateNode(XmlNode node) {
244 switch (currentNode.NodeType) {
245 case XmlNodeType.Document:
246 XmlElement docElem = ((XmlDocument)node).DocumentElement;
247 if (docElem == null) {
248 throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidXmlDocument, Res.GetString(Res.Xdom_NoRootEle)));
250 ValidateNode(docElem);
253 case XmlNodeType.DocumentFragment:
254 case XmlNodeType.EntityReference:
255 for (XmlNode child = node.FirstChild; child != null; child = child.NextSibling) {
260 case XmlNodeType.Element:
264 case XmlNodeType.Attribute: //Top-level attribute
265 XmlAttribute attr = currentNode as XmlAttribute;
266 validator.ValidateAttribute(attr.LocalName, attr.NamespaceURI, nodeValueGetter, attributeSchemaInfo);
267 if (psviAugmentation) {
268 attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo);
272 case XmlNodeType.Text:
273 validator.ValidateText(nodeValueGetter);
276 case XmlNodeType.CDATA:
277 validator.ValidateText(nodeValueGetter);
280 case XmlNodeType.Whitespace:
281 case XmlNodeType.SignificantWhitespace:
282 validator.ValidateWhitespace(nodeValueGetter);
285 case XmlNodeType.Comment:
286 case XmlNodeType.ProcessingInstruction:
290 throw new InvalidOperationException( Res.GetString( Res.Xml_UnexpectedNodeType, new string[]{ currentNode.NodeType.ToString() } ) );
294 // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
295 // Since the resource names passed to ValidateElement method are null and the function does not expose any resources
296 // it is fine to suppress the SxS warning.
297 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
298 [ResourceExposure(ResourceScope.None)]
299 private void ValidateElement() {
300 nsManager.PushScope();
301 XmlElement elementNode = currentNode as XmlElement;
302 Debug.Assert(elementNode != null);
304 XmlAttributeCollection attributes = elementNode.Attributes;
305 XmlAttribute attr = null;
307 //Find Xsi attributes that need to be processed before validating the element
308 string xsiNil = null;
309 string xsiType = null;
311 for (int i = 0; i < attributes.Count; i++) {
312 attr = attributes[i];
313 string objectNs = attr.NamespaceURI;
314 string objectName = attr.LocalName;
315 Debug.Assert(nameTable.Get(attr.NamespaceURI) != null);
316 Debug.Assert(nameTable.Get(attr.LocalName) != null);
318 if (Ref.Equal(objectNs, NsXsi)) {
319 if (Ref.Equal(objectName, XsiType)) {
320 xsiType = attr.Value;
322 else if (Ref.Equal(objectName, XsiNil)) {
326 else if (Ref.Equal(objectNs,NsXmlNs)) {
327 nsManager.AddNamespace(attr.Prefix.Length == 0 ? string.Empty : attr.LocalName, attr.Value);
330 validator.ValidateElement(elementNode.LocalName, elementNode.NamespaceURI, schemaInfo, xsiType, xsiNil, null, null);
331 ValidateAttributes(elementNode);
332 validator.ValidateEndOfAttributes(schemaInfo);
334 //If element has children, drill down
335 for (XmlNode child = elementNode.FirstChild; child != null; child = child.NextSibling) {
338 //Validate end of element
339 currentNode = elementNode; //Reset current Node for validation call back
340 validator.ValidateEndElement(schemaInfo);
341 //Get XmlName, as memberType / validity might be set now
342 if (psviAugmentation) {
343 elementNode.XmlName = document.AddXmlName(elementNode.Prefix, elementNode.LocalName, elementNode.NamespaceURI, schemaInfo);
344 if (schemaInfo.IsDefault) { //the element has a default value
345 XmlText textNode = document.CreateTextNode(schemaInfo.SchemaElement.ElementDecl.DefaultValueRaw);
346 elementNode.AppendChild(textNode);
350 nsManager.PopScope(); //Pop current namespace scope
353 private void ValidateAttributes(XmlElement elementNode) {
354 XmlAttributeCollection attributes = elementNode.Attributes;
355 XmlAttribute attr = null;
357 for (int i = 0; i < attributes.Count; i++) {
358 attr = attributes[i];
359 currentNode = attr; //For nodeValueGetter to pick up the right attribute value
360 if (Ref.Equal(attr.NamespaceURI,NsXmlNs)) { //Do not validate namespace decls
363 validator.ValidateAttribute(attr.LocalName, attr.NamespaceURI, nodeValueGetter, attributeSchemaInfo);
364 if (psviAugmentation) {
365 attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo);
369 if (psviAugmentation) {
370 //Add default attributes to the attributes collection
371 if (defaultAttributes == null) {
372 defaultAttributes = new ArrayList();
375 defaultAttributes.Clear();
377 validator.GetUnspecifiedDefaultAttributes(defaultAttributes);
378 XmlSchemaAttribute schemaAttribute = null;
379 XmlQualifiedName attrQName;
381 for (int i = 0; i < defaultAttributes.Count; i++) {
382 schemaAttribute = defaultAttributes[i] as XmlSchemaAttribute;
383 attrQName = schemaAttribute.QualifiedName;
384 Debug.Assert(schemaAttribute != null);
385 attr = document.CreateDefaultAttribute(GetDefaultPrefix(attrQName.Namespace), attrQName.Name, attrQName.Namespace);
386 SetDefaultAttributeSchemaInfo(schemaAttribute);
387 attr.XmlName = document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, attributeSchemaInfo);
388 attr.AppendChild(document.CreateTextNode(schemaAttribute.AttDef.DefaultValueRaw));
389 attributes.Append(attr);
390 XmlUnspecifiedAttribute defAttr = attr as XmlUnspecifiedAttribute;
391 if (defAttr != null) {
392 defAttr.SetSpecified(false);
398 private void SetDefaultAttributeSchemaInfo(XmlSchemaAttribute schemaAttribute) {
399 Debug.Assert(attributeSchemaInfo != null);
400 attributeSchemaInfo.Clear();
401 attributeSchemaInfo.IsDefault = true;
402 attributeSchemaInfo.IsNil = false;
403 attributeSchemaInfo.SchemaType = schemaAttribute.AttributeSchemaType;
404 attributeSchemaInfo.SchemaAttribute = schemaAttribute;
406 //Get memberType for default attribute
407 SchemaAttDef attributeDef = schemaAttribute.AttDef;
408 if (attributeDef.Datatype.Variety == XmlSchemaDatatypeVariety.Union) {
409 XsdSimpleValue simpleValue = attributeDef.DefaultValueTyped as XsdSimpleValue;
410 Debug.Assert(simpleValue != null);
411 attributeSchemaInfo.MemberType = simpleValue.XmlType;
413 attributeSchemaInfo.Validity = XmlSchemaValidity.Valid;
416 private string GetDefaultPrefix(string attributeNS) {
417 IDictionary<string,string> namespaceDecls = NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.All);
418 string defaultPrefix = null;
420 attributeNS = nameTable.Add(attributeNS); //atomize ns
422 foreach (KeyValuePair<string,string> pair in namespaceDecls) {
423 defaultNS = nameTable.Add(pair.Value);
424 if (object.ReferenceEquals(defaultNS, attributeNS)) {
425 defaultPrefix = pair.Key;
426 if (defaultPrefix.Length != 0) { //Locate first non-empty prefix
427 return defaultPrefix;
431 return defaultPrefix;
434 private object GetNodeValue() {
435 return currentNode.Value;
438 //Code for finding type during partial validation
439 private XmlSchemaObject FindSchemaInfo(XmlElement elementToValidate) {
440 isPartialTreeValid = true;
441 Debug.Assert(elementToValidate.ParentNode.NodeType != XmlNodeType.Document); //Handle if it is the documentElement seperately
443 //Create nodelist to navigate down again
444 XmlNode currentNode = elementToValidate;
445 IXmlSchemaInfo parentSchemaInfo = null;
448 //Check common case of parent node first
449 XmlNode parentNode = currentNode.ParentNode;
451 parentSchemaInfo = parentNode.SchemaInfo;
452 if (parentSchemaInfo.SchemaElement != null || parentSchemaInfo.SchemaType != null) {
453 break; //Found ancestor with schemaInfo
455 CheckNodeSequenceCapacity(nodeIndex);
456 nodeSequenceToValidate[nodeIndex++] = parentNode;
457 parentNode = parentNode.ParentNode;
458 } while (parentNode != null);
460 if (parentNode == null) { //Did not find any type info all the way to the root, currentNode is Document || DocumentFragment
461 nodeIndex = nodeIndex - 1; //Subtract the one for document and set the node to null
462 nodeSequenceToValidate[nodeIndex] = null;
463 return GetTypeFromAncestors(elementToValidate, null, nodeIndex);
466 //Start validating down from the parent or ancestor that has schema info and shallow validate all previous siblings
467 //to correctly ascertain particle for current node
468 CheckNodeSequenceCapacity(nodeIndex);
469 nodeSequenceToValidate[nodeIndex++] = parentNode;
470 XmlSchemaObject ancestorSchemaObject = parentSchemaInfo.SchemaElement;
471 if (ancestorSchemaObject == null) {
472 ancestorSchemaObject = parentSchemaInfo.SchemaType;
474 return GetTypeFromAncestors(elementToValidate, ancestorSchemaObject, nodeIndex);
479 /*private XmlSchemaElement GetTypeFromParent(XmlElement elementToValidate, XmlSchemaComplexType parentSchemaType) {
480 XmlQualifiedName elementName = new XmlQualifiedName(elementToValidate.LocalName, elementToValidate.NamespaceURI);
481 XmlSchemaElement elem = parentSchemaType.LocalElements[elementName] as XmlSchemaElement;
482 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
483 SchemaInfo compiledSchemaInfo = schemas.CompiledInfo;
484 XmlSchemaElement memberElem = compiledSchemaInfo.GetElement(elementName);
485 if (memberElem != null) {
490 private void CheckNodeSequenceCapacity(int currentIndex) {
491 if (nodeSequenceToValidate == null) { //Normally users would call Validate one level down, this allows for 4
492 nodeSequenceToValidate = new XmlNode[4];
494 else if (currentIndex >= nodeSequenceToValidate.Length -1 ) { //reached capacity of array, Need to increase capacity to twice the initial
495 XmlNode[] newNodeSequence = new XmlNode[nodeSequenceToValidate.Length * 2];
496 Array.Copy(nodeSequenceToValidate, 0, newNodeSequence, 0, nodeSequenceToValidate.Length);
497 nodeSequenceToValidate = newNodeSequence;
501 private XmlSchemaAttribute FindSchemaInfo(XmlAttribute attributeToValidate) {
502 XmlElement parentElement = attributeToValidate.OwnerElement;
503 XmlSchemaObject schemaObject = FindSchemaInfo(parentElement);
504 XmlSchemaComplexType elementSchemaType = GetComplexType(schemaObject);
505 if (elementSchemaType == null) {
508 XmlQualifiedName attName = new XmlQualifiedName(attributeToValidate.LocalName, attributeToValidate.NamespaceURI);
509 XmlSchemaAttribute schemaAttribute = elementSchemaType.AttributeUses[attName] as XmlSchemaAttribute;
510 if (schemaAttribute == null) {
511 XmlSchemaAnyAttribute anyAttribute = elementSchemaType.AttributeWildcard;
512 if (anyAttribute != null) {
513 if (anyAttribute.NamespaceList.Allows(attName)){ //Match wildcard against global attribute
514 schemaAttribute = schemas.GlobalAttributes[attName] as XmlSchemaAttribute;
518 return schemaAttribute;
521 private XmlSchemaObject GetTypeFromAncestors(XmlElement elementToValidate, XmlSchemaObject ancestorType, int ancestorsCount) {
523 //schemaInfo is currentNode's schemaInfo
524 validator = CreateTypeFinderValidator(ancestorType);
525 schemaInfo = new XmlSchemaInfo();
527 //start at the ancestor to start validating
528 int startIndex = ancestorsCount - 1;
530 bool ancestorHasWildCard = AncestorTypeHasWildcard(ancestorType);
531 for (int i = startIndex; i >= 0; i--) {
532 XmlNode node = nodeSequenceToValidate[i];
533 XmlElement currentElement = node as XmlElement;
534 ValidateSingleElement(currentElement, false, schemaInfo);
535 if (!ancestorHasWildCard) { //store type if ancestor does not have wildcard in its content model
536 currentElement.XmlName = document.AddXmlName(currentElement.Prefix, currentElement.LocalName, currentElement.NamespaceURI, schemaInfo);
537 //update wildcard flag
538 ancestorHasWildCard = AncestorTypeHasWildcard(schemaInfo.SchemaElement);
541 validator.ValidateEndOfAttributes(null);
543 ValidateChildrenTillNextAncestor(node, nodeSequenceToValidate[i - 1]);
546 ValidateChildrenTillNextAncestor(node, elementToValidate);
550 Debug.Assert(nodeSequenceToValidate[0] == elementToValidate.ParentNode);
551 //validate element whose type is needed,
552 ValidateSingleElement(elementToValidate, false, schemaInfo);
554 XmlSchemaObject schemaInfoFound = null;
555 if (schemaInfo.SchemaElement != null) {
556 schemaInfoFound = schemaInfo.SchemaElement;
559 schemaInfoFound = schemaInfo.SchemaType;
561 if (schemaInfoFound == null) { //Detect if the node was validated lax or skip
562 if (validator.CurrentProcessContents == XmlSchemaContentProcessing.Skip) {
563 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.
564 return XmlSchemaComplexType.AnyTypeSkip;
567 else if (validator.CurrentProcessContents == XmlSchemaContentProcessing.Lax) {
568 return XmlSchemaComplexType.AnyType;
571 return schemaInfoFound;
574 private bool AncestorTypeHasWildcard(XmlSchemaObject ancestorType) {
575 XmlSchemaComplexType ancestorSchemaType = GetComplexType(ancestorType);
576 if (ancestorType != null) {
577 return ancestorSchemaType.HasWildCard;
582 private XmlSchemaComplexType GetComplexType(XmlSchemaObject schemaObject) {
583 if (schemaObject == null) {
586 XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement;
587 XmlSchemaComplexType complexType = null;
588 if (schemaElement != null) {
589 complexType = schemaElement.ElementSchemaType as XmlSchemaComplexType;
592 complexType = schemaObject as XmlSchemaComplexType;
597 // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
598 // Since the resource names passed to ValidateElement method are null and the function does not expose any resources
599 // it is fine to supress the warning.
600 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
601 [ResourceExposure(ResourceScope.None)]
602 private void ValidateSingleElement(XmlElement elementNode, bool skipToEnd, XmlSchemaInfo newSchemaInfo) {
603 nsManager.PushScope();
604 Debug.Assert(elementNode != null);
606 XmlAttributeCollection attributes = elementNode.Attributes;
607 XmlAttribute attr = null;
609 //Find Xsi attributes that need to be processed before validating the element
610 string xsiNil = null;
611 string xsiType = null;
613 for (int i = 0; i < attributes.Count; i++) {
614 attr = attributes[i];
615 string objectNs = attr.NamespaceURI;
616 string objectName = attr.LocalName;
617 Debug.Assert(nameTable.Get(attr.NamespaceURI) != null);
618 Debug.Assert(nameTable.Get(attr.LocalName) != null);
620 if (Ref.Equal(objectNs, NsXsi)) {
621 if (Ref.Equal(objectName, XsiType)) {
622 xsiType = attr.Value;
624 else if (Ref.Equal(objectName, XsiNil)) {
628 else if (Ref.Equal(objectNs,NsXmlNs)) {
629 nsManager.AddNamespace(attr.Prefix.Length == 0 ? string.Empty : attr.LocalName, attr.Value);
632 validator.ValidateElement(elementNode.LocalName, elementNode.NamespaceURI, newSchemaInfo, xsiType, xsiNil, null, null);
633 //Validate end of element
635 validator.ValidateEndOfAttributes(newSchemaInfo);
636 validator.SkipToEndElement(newSchemaInfo);
637 nsManager.PopScope(); //Pop current namespace scope
641 private void ValidateChildrenTillNextAncestor(XmlNode parentNode, XmlNode childToStopAt) {
644 for (child = parentNode.FirstChild; child != null; child = child.NextSibling) {
645 if (child == childToStopAt) {
648 switch (child.NodeType) {
649 case XmlNodeType.EntityReference:
650 ValidateChildrenTillNextAncestor(child, childToStopAt);
653 case XmlNodeType.Element: //Flat validation, do not drill down into children
654 ValidateSingleElement(child as XmlElement, true, null);
657 case XmlNodeType.Text:
658 case XmlNodeType.CDATA:
659 validator.ValidateText(child.Value);
662 case XmlNodeType.Whitespace:
663 case XmlNodeType.SignificantWhitespace:
664 validator.ValidateWhitespace(child.Value);
667 case XmlNodeType.Comment:
668 case XmlNodeType.ProcessingInstruction:
672 throw new InvalidOperationException( Res.GetString( Res.Xml_UnexpectedNodeType, new string[]{ currentNode.NodeType.ToString() } ) );
675 Debug.Assert(child == childToStopAt);
678 private XmlSchemaValidator CreateTypeFinderValidator(XmlSchemaObject partialValidationType) {
679 XmlSchemaValidator findTypeValidator = new XmlSchemaValidator(document.NameTable, document.Schemas, this.nsManager, XmlSchemaValidationFlags.None);
680 findTypeValidator.ValidationEventHandler += new ValidationEventHandler(TypeFinderCallBack);
681 if (partialValidationType != null) {
682 findTypeValidator.Initialize(partialValidationType);
684 else { //If we walked up to the root and no schemaInfo was there, start validating from root
685 findTypeValidator.Initialize();
687 return findTypeValidator;
690 private void TypeFinderCallBack(object sender, ValidationEventArgs arg) {
691 if (arg.Severity == XmlSeverityType.Error) {
692 isPartialTreeValid = false;
696 private void InternalValidationCallBack(object sender, ValidationEventArgs arg) {
697 if (arg.Severity == XmlSeverityType.Error) {
700 XmlSchemaValidationException ex = arg.Exception as XmlSchemaValidationException;
701 Debug.Assert(ex != null);
702 ex.SetSourceObject(currentNode);
703 if (this.eventHandler != null) { //Invoke user's event handler
704 eventHandler(sender, arg);
706 else if (arg.Severity == XmlSeverityType.Error) {