1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaValidator.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
9 using System.Collections;
10 using System.Collections.Generic;
13 using System.Diagnostics;
15 using System.Xml.Schema;
16 using System.Xml.XPath;
17 using System.Threading;
18 using System.Runtime.Versioning;
20 namespace System.Xml.Schema {
22 public delegate object XmlValueGetter();
25 public enum XmlSchemaValidationFlags {
27 ProcessInlineSchema = 0x0001,
28 ProcessSchemaLocation = 0x0002,
29 ReportValidationWarnings = 0x0004,
30 ProcessIdentityConstraints = 0x0008,
31 AllowXmlAttributes = 0x0010,
34 internal enum ValidatorState {
48 internal class IdRefNode {
52 internal IdRefNode Next;
54 internal IdRefNode(IdRefNode next, string id, int lineNo, int linePos) {
57 this.LinePos = linePos;
62 public sealed class XmlSchemaValidator {
65 private XmlSchemaSet schemaSet;
68 private XmlSchemaValidationFlags validationFlags;
71 private int startIDConstraint = -1;
72 private const int STACK_INCREMENT = 10;
74 private bool rootHasSchema;
77 private bool attrValid;
78 private bool checkEntity;
80 private SchemaInfo compiledSchemaInfo;
81 private IDtdInfo dtdSchemaInfo;
82 private Hashtable validatedNamespaces;
84 private HWStack validationStack; // validaton contexts
85 private ValidationState context; // current context
86 private ValidatorState currentState;
89 private Hashtable attPresence; //(AttName Vs AttIndex)
90 private SchemaAttDef wildID;
92 private Hashtable IDs;
93 private IdRefNode idRefListHead;
96 XmlQualifiedName contextQName;
98 //Avoid SchemaNames creation
100 private string NsXsi;
101 private string NsXmlNs;
102 private string NsXml;
105 private XmlSchemaObject partialValidationType;
108 private StringBuilder textValue;
111 private ValidationEventHandler eventHandler;
112 private object validationEventSender;
113 private XmlNameTable nameTable;
114 private IXmlLineInfo positionInfo;
115 private IXmlLineInfo dummyPositionInfo;
117 private XmlResolver xmlResolver;
118 private Uri sourceUri;
119 private string sourceUriString;
120 private IXmlNamespaceResolver nsResolver;
122 private XmlSchemaContentProcessing processContents = XmlSchemaContentProcessing.Strict;
124 private static XmlSchemaAttribute xsiTypeSO;
125 private static XmlSchemaAttribute xsiNilSO;
126 private static XmlSchemaAttribute xsiSLSO;
127 private static XmlSchemaAttribute xsiNoNsSLSO;
129 //Xsi Attributes that are atomized
130 private string xsiTypeString;
131 private string xsiNilString;
132 private string xsiSchemaLocationString;
133 private string xsiNoNamespaceSchemaLocationString;
135 //Xsi Attributes parsing
136 private static readonly XmlSchemaDatatype dtQName = XmlSchemaDatatype.FromXmlTokenizedTypeXsd(XmlTokenizedType.QName);
137 private static readonly XmlSchemaDatatype dtCDATA = XmlSchemaDatatype.FromXmlTokenizedType(XmlTokenizedType.CDATA);
138 private static readonly XmlSchemaDatatype dtStringArray = dtCDATA.DeriveByList(null);
140 //Error message constants
141 private const string Quote = "'";
144 private static XmlSchemaParticle[] EmptyParticleArray = new XmlSchemaParticle[0];
145 private static XmlSchemaAttribute[] EmptyAttributeArray = new XmlSchemaAttribute[0];
147 //Whitespace check for text nodes
148 XmlCharType xmlCharType = XmlCharType.Instance;
150 internal static bool[,] ValidStates = new bool[12,12] {
151 /*ValidatorState.None*/ /*ValidatorState.Start /*ValidatorState.TopLevelAttribute*/ /*ValidatorState.TopLevelTOrWS*/ /*ValidatorState.Element*/ /*ValidatorState.Attribute*/ /*ValidatorState.EndAttributes*/ /*ValidatorState.Text/ /*ValidatorState.WS/* /*ValidatorState.EndElement*/ /*ValidatorState.SkipToEndElement*/ /*ValidatorState.Finish*/
152 /*ValidatorState.None*/ { true, true, false, false, false, false, false, false, false, false, false, false},
153 /*ValidatorState.Start*/ { false, true, true, true, true, false, false, false, false, false, false, true },
154 /*ValidatorState.TopLevelAttribute*/{ false, false, false, false, false, false, false, false, false, false, false, true },
155 /*ValidatorState.TopLevelTextOrWS*/ { false, false, false, true, true, false, false, false, false, false, false, true },
156 /*ValidatorState.Element*/ { false, false, false, true, false, true, true, false, false, true, true, false},
157 /*ValidatorState.Attribute*/ { false, false, false, false, false, true, true, false, false, true, true, false},
158 /*ValidatorState.EndAttributes*/ { false, false, false, false, true, false, false, true, true, true, true, false},
159 /*ValidatorState.Text*/ { false, false, false, false, true, false, false, true, true, true, true, false},
160 /*ValidatorState.Whitespace*/ { false, false, false, false, true, false, false, true, true, true, true, false},
161 /*ValidatorState.EndElement*/ { false, false, false, true, true, false, false, true, true, true, true /*?*/, true },
162 /*ValidatorState.SkipToEndElement*/ { false, false, false, true, true, false, false, true, true, true, true, true },
163 /*ValidatorState.Finish*/ { false, true, false, false, false, false, false, false, false, false, false, false},
166 private static string[] MethodNames = new string[12] {"None", "Initialize", "top-level ValidateAttribute", "top-level ValidateText or ValidateWhitespace", "ValidateElement", "ValidateAttribute", "ValidateEndOfAttributes", "ValidateText", "ValidateWhitespace", "ValidateEndElement", "SkipToEndElement", "EndValidation" };
168 public XmlSchemaValidator(XmlNameTable nameTable, XmlSchemaSet schemas, IXmlNamespaceResolver namespaceResolver, XmlSchemaValidationFlags validationFlags) {
169 if (nameTable == null) {
170 throw new ArgumentNullException("nameTable");
172 if (schemas == null) {
173 throw new ArgumentNullException("schemas");
175 if (namespaceResolver == null) {
176 throw new ArgumentNullException("namespaceResolver");
178 this.nameTable = nameTable;
179 this.nsResolver = namespaceResolver;
180 this.validationFlags = validationFlags;
183 if ( ((validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0) || ((validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0) ) { //Process schema hints in xml document, hence user's set might change
184 this.schemaSet = new XmlSchemaSet(nameTable);
185 this.schemaSet.ValidationEventHandler += schemas.GetEventHandler();
186 this.schemaSet.CompilationSettings = schemas.CompilationSettings;
187 this.schemaSet.XmlResolver = schemas.GetResolver();
188 this.schemaSet.Add(schemas);
189 validatedNamespaces = new Hashtable();
191 else { //Use the same set from the user
192 this.schemaSet = schemas;
197 private void Init() {
198 validationStack = new HWStack(STACK_INCREMENT);
199 attPresence = new Hashtable();
200 Push(XmlQualifiedName.Empty);
202 dummyPositionInfo = new PositionInfo(); //Dummy position info, will return (0,0) if user does not set the LineInfoProvider property
203 positionInfo = dummyPositionInfo;
204 validationEventSender = this;
205 currentState = ValidatorState.None;
206 textValue = new StringBuilder(100);
207 xmlResolver = System.Xml.XmlConfiguration.XmlReaderSection.CreateDefaultResolver();
208 contextQName = new XmlQualifiedName(); //Re-use qname
211 RecompileSchemaSet(); //Gets compiled info from set as well
212 //Get already Atomized strings
213 NsXs = nameTable.Add(XmlReservedNs.NsXs);
214 NsXsi = nameTable.Add(XmlReservedNs.NsXsi);
215 NsXmlNs = nameTable.Add(XmlReservedNs.NsXmlNs);
216 NsXml = nameTable.Add(XmlReservedNs.NsXml);
217 xsiTypeString = nameTable.Add("type");
218 xsiNilString = nameTable.Add("nil");
219 xsiSchemaLocationString = nameTable.Add("schemaLocation");
220 xsiNoNamespaceSchemaLocationString = nameTable.Add("noNamespaceSchemaLocation");
223 private void Reset() {
225 rootHasSchema = true;
226 while(validationStack.Length > 1) { //Clear all other context from stack
227 validationStack.Pop();
229 startIDConstraint = -1;
230 partialValidationType = null;
232 //Clear previous tables
236 if (ProcessSchemaHints) {
237 validatedNamespaces.Clear();
242 public XmlResolver XmlResolver {
248 public IXmlLineInfo LineInfoProvider {
253 if (value == null) { //If value is null, retain the default dummy line info
254 this.positionInfo = dummyPositionInfo;
257 this.positionInfo = value;
262 public Uri SourceUri {
268 sourceUriString = sourceUri.ToString();
272 public object ValidationEventSender {
274 return validationEventSender;
277 validationEventSender = value;
281 public event ValidationEventHandler ValidationEventHandler {
283 eventHandler += value;
286 eventHandler -= value;
292 public void AddSchema(XmlSchema schema) {
293 if (schema == null) {
294 throw new ArgumentNullException("schema");
296 if ((validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) == 0) { //Do not process schema if processInlineSchema is not set
299 string tns = schema.TargetNamespace;
303 //Store the previous locations
304 Hashtable schemaLocations = schemaSet.SchemaLocations;
305 DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count];
306 schemaLocations.CopyTo(oldLocations, 0);
309 Debug.Assert(validatedNamespaces != null);
310 if (validatedNamespaces[tns] != null && schemaSet.FindSchemaByNSAndUrl(schema.BaseUri, tns, oldLocations) == null) {
311 SendValidationEvent(Res.Sch_ComponentAlreadySeenForNS, tns, XmlSeverityType.Error);
313 if (schema.ErrorCount == 0) {
315 schemaSet.Add(schema);
316 RecompileSchemaSet();
318 catch(XmlSchemaException e) {
319 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {schema.BaseUri.ToString(), e.Message},e);
321 for (int i = 0; i < schema.ImportedSchemas.Count; ++i) { //Check for its imports
322 XmlSchema impSchema = (XmlSchema)schema.ImportedSchemas[i];
323 tns = impSchema.TargetNamespace;
327 if (validatedNamespaces[tns] != null && schemaSet.FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) {
328 SendValidationEvent(Res.Sch_ComponentAlreadySeenForNS, tns, XmlSeverityType.Error);
329 schemaSet.RemoveRecursive(schema);
336 public void Initialize() {
337 if (currentState != ValidatorState.None && currentState != ValidatorState.Finish) {
338 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStateTransition, new string[] { MethodNames[(int)currentState], MethodNames[(int)ValidatorState.Start] }));
340 currentState = ValidatorState.Start;
344 public void Initialize(XmlSchemaObject partialValidationType) {
345 if (currentState != ValidatorState.None && currentState != ValidatorState.Finish) {
346 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStateTransition, new string[] { MethodNames[(int)currentState], MethodNames[(int)ValidatorState.Start] }));
348 if (partialValidationType == null) {
349 throw new ArgumentNullException("partialValidationType");
351 if (!(partialValidationType is XmlSchemaElement || partialValidationType is XmlSchemaAttribute || partialValidationType is XmlSchemaType)) {
352 throw new ArgumentException(Res.GetString(Res.Sch_InvalidPartialValidationType));
354 currentState = ValidatorState.Start;
356 this.partialValidationType = partialValidationType;
359 // SxS: This method passes null as resource names and does not expose any resources to the caller.
360 // It's OK to suppress the SxS warning.
361 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
362 [ResourceExposure(ResourceScope.None)]
363 public void ValidateElement(string localName, string namespaceUri, XmlSchemaInfo schemaInfo) {
364 ValidateElement(localName, namespaceUri, schemaInfo, null, null, null, null);
367 [ResourceConsumption(ResourceScope.Machine)]
368 [ResourceExposure(ResourceScope.Machine)]
369 public void ValidateElement(string localName, string namespaceUri, XmlSchemaInfo schemaInfo, string xsiType, string xsiNil, string xsiSchemaLocation, string xsiNoNamespaceSchemaLocation) {
370 if (localName == null) {
371 throw new ArgumentNullException("localName");
373 if (namespaceUri == null) {
374 throw new ArgumentNullException("namespaceUri");
377 CheckStateTransition(ValidatorState.Element, MethodNames[(int)ValidatorState.Element]);
380 contextQName.Init(localName, namespaceUri);
381 XmlQualifiedName elementName = contextQName;
383 bool invalidElementInContext;
384 object particle = ValidateElementContext(elementName, out invalidElementInContext); //Check element name is allowed in current position
385 SchemaElementDecl elementDecl = FastGetElementDecl(elementName, particle);
387 //Change context to current element and update element decl
390 //Change current context's error state depending on whether this element was validated in its context correctly
391 if (invalidElementInContext) {
392 context.Validity = XmlSchemaValidity.Invalid;
395 //Check if there are Xsi attributes
396 if ((validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0 && xmlResolver != null) { //we should process schema location
397 ProcessSchemaLocations(xsiSchemaLocation, xsiNoNamespaceSchemaLocation);
400 if (processContents != XmlSchemaContentProcessing.Skip) {
401 if (elementDecl == null && partialValidationType == null) { //Since new schemaLocations might have been added, try for decl from the set again only if no PVType is set
402 elementDecl = compiledSchemaInfo.GetElementDecl(elementName);
404 bool declFound = elementDecl != null;
405 if (xsiType != null || xsiNil != null) {
406 elementDecl = CheckXsiTypeAndNil(elementDecl, xsiType, xsiNil, ref declFound);
408 if (elementDecl == null) {
409 ThrowDeclNotFoundWarningOrError(declFound); //This updates processContents
413 context.ElementDecl = elementDecl;
414 XmlSchemaElement localSchemaElement = null;
415 XmlSchemaType localSchemaType = null;
416 if (elementDecl != null) {
417 CheckElementProperties();
418 attPresence.Clear(); //Clear attributes hashtable for every element
419 context.NeedValidateChildren = processContents != XmlSchemaContentProcessing.Skip;
420 ValidateStartElementIdentityConstraints(); //Need attr collection validated here
421 elementDecl.ContentValidator.InitValidation(context);
423 localSchemaType = elementDecl.SchemaType;
424 localSchemaElement = GetSchemaElement();
427 if (schemaInfo != null) {
428 schemaInfo.SchemaType = localSchemaType;
429 schemaInfo.SchemaElement = localSchemaElement;
430 schemaInfo.IsNil = context.IsNill;
431 schemaInfo.Validity = context.Validity;
433 if (ProcessSchemaHints) {
434 if (validatedNamespaces[namespaceUri] == null) {
435 validatedNamespaces.Add(namespaceUri, namespaceUri);
444 public object ValidateAttribute(string localName, string namespaceUri, string attributeValue, XmlSchemaInfo schemaInfo) {
445 if (attributeValue == null) {
446 throw new ArgumentNullException("attributeValue");
448 return ValidateAttribute(localName, namespaceUri, null, attributeValue, schemaInfo);
451 public object ValidateAttribute(string localName, string namespaceUri, XmlValueGetter attributeValue, XmlSchemaInfo schemaInfo) {
452 if (attributeValue == null) {
453 throw new ArgumentNullException("attributeValue");
455 return ValidateAttribute(localName, namespaceUri, attributeValue, null, schemaInfo);
458 private object ValidateAttribute(string lName, string ns, XmlValueGetter attributeValueGetter, string attributeStringValue, XmlSchemaInfo schemaInfo) {
460 throw new ArgumentNullException("localName");
463 throw new ArgumentNullException("namespaceUri");
466 ValidatorState toState = validationStack.Length > 1 ? ValidatorState.Attribute : ValidatorState.TopLevelAttribute;
467 CheckStateTransition(toState, MethodNames[(int)toState]);
469 object typedVal = null;
471 XmlSchemaValidity localValidity = XmlSchemaValidity.NotKnown;
472 XmlSchemaAttribute localAttribute = null;
473 XmlSchemaSimpleType localMemberType = null;
475 ns = nameTable.Add(ns);
476 if(Ref.Equal(ns,NsXmlNs)) {
480 SchemaAttDef attributeDef = null;
481 SchemaElementDecl currentElementDecl = context.ElementDecl;
482 XmlQualifiedName attQName = new XmlQualifiedName(lName, ns);
483 if (attPresence[attQName] != null) { //this attribute already checked as it is duplicate;
484 SendValidationEvent(Res.Sch_DuplicateAttribute, attQName.ToString());
485 if (schemaInfo != null) {
491 if (!Ref.Equal(ns,NsXsi)) { //
492 XmlSchemaObject pvtAttribute = currentState == ValidatorState.TopLevelAttribute ? partialValidationType : null;
493 AttributeMatchState attributeMatchState;
494 attributeDef = compiledSchemaInfo.GetAttributeXsd(currentElementDecl, attQName, pvtAttribute, out attributeMatchState);
496 switch (attributeMatchState) {
497 case AttributeMatchState.UndeclaredElementAndAttribute:
498 if((attributeDef = CheckIsXmlAttribute(attQName)) != null) { //Try for xml attribute
499 goto case AttributeMatchState.AttributeFound;
501 if (currentElementDecl == null
502 && processContents == XmlSchemaContentProcessing.Strict
503 && attQName.Namespace.Length != 0
504 && compiledSchemaInfo.Contains(attQName.Namespace)
507 SendValidationEvent(Res.Sch_UndeclaredAttribute, attQName.ToString());
509 else if (processContents != XmlSchemaContentProcessing.Skip) {
510 SendValidationEvent(Res.Sch_NoAttributeSchemaFound, attQName.ToString(), XmlSeverityType.Warning);
514 case AttributeMatchState.UndeclaredAttribute:
515 if((attributeDef = CheckIsXmlAttribute(attQName)) != null) {
516 goto case AttributeMatchState.AttributeFound;
520 SendValidationEvent(Res.Sch_UndeclaredAttribute, attQName.ToString());
524 case AttributeMatchState.ProhibitedAnyAttribute:
525 if((attributeDef = CheckIsXmlAttribute(attQName)) != null) {
526 goto case AttributeMatchState.AttributeFound;
530 SendValidationEvent(Res.Sch_ProhibitedAttribute, attQName.ToString());
534 case AttributeMatchState.ProhibitedAttribute:
536 SendValidationEvent(Res.Sch_ProhibitedAttribute, attQName.ToString());
539 case AttributeMatchState.AttributeNameMismatch:
541 SendValidationEvent(Res.Sch_SchemaAttributeNameMismatch, new string[] { attQName.ToString(), ((XmlSchemaAttribute)pvtAttribute).QualifiedName.ToString()});
544 case AttributeMatchState.ValidateAttributeInvalidCall:
545 Debug.Assert(currentState == ValidatorState.TopLevelAttribute); //Re-set state back to start on error with partial validation type
546 currentState = ValidatorState.Start;
548 SendValidationEvent(Res.Sch_ValidateAttributeInvalidCall, string.Empty);
551 case AttributeMatchState.AnyIdAttributeFound:
552 if (wildID == null) {
553 wildID = attributeDef;
554 Debug.Assert(currentElementDecl != null);
555 XmlSchemaComplexType ct = currentElementDecl.SchemaType as XmlSchemaComplexType;
556 Debug.Assert(ct != null);
557 if (ct.ContainsIdAttribute(false)) {
558 SendValidationEvent(Res.Sch_AttrUseAndWildId, string.Empty);
561 goto case AttributeMatchState.AttributeFound;
564 else { //More than one attribute per element cannot match wildcard if both their types are derived from ID
565 SendValidationEvent(Res.Sch_MoreThanOneWildId, string.Empty);
569 case AttributeMatchState.AttributeFound:
570 Debug.Assert(attributeDef != null);
571 localAttribute = attributeDef.SchemaAttribute;
572 if (currentElementDecl != null) { //Have to add to hashtable to check whether to add default attributes
573 attPresence.Add(attQName, attributeDef);
576 if (attributeValueGetter != null) {
577 attValue = attributeValueGetter();
580 attValue = attributeStringValue;
582 typedVal = CheckAttributeValue(attValue, attributeDef);
583 XmlSchemaDatatype datatype = attributeDef.Datatype;
584 if (datatype.Variety == XmlSchemaDatatypeVariety.Union && typedVal != null) { //Unpack the union
585 XsdSimpleValue simpleValue = typedVal as XsdSimpleValue;
586 Debug.Assert(simpleValue != null);
588 localMemberType = simpleValue.XmlType;
589 datatype = simpleValue.XmlType.Datatype;
590 typedVal = simpleValue.TypedValue;
592 CheckTokenizedTypes(datatype, typedVal, true);
593 if (HasIdentityConstraints) {
594 AttributeIdentityConstraints(attQName.Name, attQName.Namespace, typedVal, attValue.ToString(), datatype);
598 case AttributeMatchState.AnyAttributeLax:
599 SendValidationEvent(Res.Sch_NoAttributeSchemaFound, attQName.ToString(), XmlSeverityType.Warning);
602 case AttributeMatchState.AnyAttributeSkip:
609 else { //Attribute from xsi namespace
610 lName = nameTable.Add(lName);
611 if (Ref.Equal(lName, xsiTypeString) || Ref.Equal(lName, xsiNilString) || Ref.Equal(lName, xsiSchemaLocationString) || Ref.Equal(lName, xsiNoNamespaceSchemaLocationString)) {
612 attPresence.Add(attQName, SchemaAttDef.Empty);
616 SendValidationEvent(Res.Sch_NotXsiAttribute, attQName.ToString());
621 localValidity = XmlSchemaValidity.Invalid;
623 else if (attributeDef != null) {
624 localValidity = XmlSchemaValidity.Valid;
626 if (schemaInfo != null) {
627 schemaInfo.SchemaAttribute = localAttribute;
628 schemaInfo.SchemaType = localAttribute == null ? null : localAttribute.AttributeSchemaType;
629 schemaInfo.MemberType = localMemberType;
630 schemaInfo.IsDefault = false;
631 schemaInfo.Validity = localValidity;
633 if (ProcessSchemaHints) {
634 if (validatedNamespaces[ns] == null) {
635 validatedNamespaces.Add(ns, ns);
641 public void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes) {
642 if (defaultAttributes == null) {
643 throw new ArgumentNullException("defaultAttributes");
645 CheckStateTransition(ValidatorState.Attribute, "GetUnspecifiedDefaultAttributes");
646 GetUnspecifiedDefaultAttributes(defaultAttributes, false);
649 public void ValidateEndOfAttributes(XmlSchemaInfo schemaInfo) {
650 CheckStateTransition(ValidatorState.EndOfAttributes, MethodNames[(int)ValidatorState.EndOfAttributes]);
651 //Check required attributes
652 SchemaElementDecl currentElementDecl = context.ElementDecl;
653 if (currentElementDecl != null && currentElementDecl.HasRequiredAttribute) {
654 context.CheckRequiredAttribute = false;
655 CheckRequiredAttributes(currentElementDecl);
657 if (schemaInfo != null) { //set validity depending on whether all required attributes were validated successfully
658 schemaInfo.Validity = context.Validity;
662 public void ValidateText(string elementValue) {
663 if (elementValue == null) {
664 throw new ArgumentNullException("elementValue");
666 ValidateText(elementValue, null);
669 public void ValidateText(XmlValueGetter elementValue) {
670 if (elementValue == null) {
671 throw new ArgumentNullException("elementValue");
673 ValidateText(null, elementValue);
676 private void ValidateText(string elementStringValue, XmlValueGetter elementValueGetter) {
677 ValidatorState toState = validationStack.Length > 1 ? ValidatorState.Text : ValidatorState.TopLevelTextOrWS;
678 CheckStateTransition(toState, MethodNames[(int)toState]);
680 if (context.NeedValidateChildren) {
681 if (context.IsNill) {
682 SendValidationEvent(Res.Sch_ContentInNill, QNameString(context.LocalName, context.Namespace));
685 XmlSchemaContentType contentType = context.ElementDecl.ContentValidator.ContentType;
686 switch(contentType) {
687 case XmlSchemaContentType.Empty:
688 SendValidationEvent(Res.Sch_InvalidTextInEmpty, string.Empty);
691 case XmlSchemaContentType.TextOnly:
692 if (elementValueGetter != null) {
693 SaveTextValue(elementValueGetter());
696 SaveTextValue(elementStringValue);
700 case XmlSchemaContentType.ElementOnly:
701 string textValue = elementValueGetter != null ? elementValueGetter().ToString() : elementStringValue;
702 if(xmlCharType.IsOnlyWhitespace(textValue)) {
705 ArrayList names = context.ElementDecl.ContentValidator.ExpectedParticles(context, false, schemaSet);
706 if (names == null || names.Count == 0) {
707 SendValidationEvent(Res.Sch_InvalidTextInElement, BuildElementName(context.LocalName, context.Namespace));
710 Debug.Assert(names.Count > 0);
711 SendValidationEvent(Res.Sch_InvalidTextInElementExpecting, new string[] { BuildElementName(context.LocalName, context.Namespace), PrintExpectedElements(names, true) });
715 case XmlSchemaContentType.Mixed:
716 if (context.ElementDecl.DefaultValueTyped != null) {
717 if (elementValueGetter != null) {
718 SaveTextValue(elementValueGetter());
721 SaveTextValue(elementStringValue);
729 public void ValidateWhitespace(string elementValue) {
730 if (elementValue == null) {
731 throw new ArgumentNullException("elementValue");
733 ValidateWhitespace(elementValue, null);
736 public void ValidateWhitespace(XmlValueGetter elementValue) {
737 if (elementValue == null) {
738 throw new ArgumentNullException("elementValue");
740 ValidateWhitespace(null, elementValue);
743 private void ValidateWhitespace(string elementStringValue, XmlValueGetter elementValueGetter) {
744 ValidatorState toState = validationStack.Length > 1 ? ValidatorState.Whitespace : ValidatorState.TopLevelTextOrWS;
745 CheckStateTransition(toState, MethodNames[(int)toState]);
747 if (context.NeedValidateChildren) {
748 if (context.IsNill) {
749 SendValidationEvent(Res.Sch_ContentInNill, QNameString(context.LocalName, context.Namespace));
751 XmlSchemaContentType contentType = context.ElementDecl.ContentValidator.ContentType;
752 switch (contentType) {
753 case XmlSchemaContentType.Empty:
754 SendValidationEvent(Res.Sch_InvalidWhitespaceInEmpty, string.Empty);
757 case XmlSchemaContentType.TextOnly:
758 if (elementValueGetter != null) {
759 SaveTextValue(elementValueGetter());
762 SaveTextValue(elementStringValue);
766 case XmlSchemaContentType.Mixed:
767 if (context.ElementDecl.DefaultValueTyped != null) {
768 if (elementValueGetter != null) {
769 SaveTextValue(elementValueGetter());
772 SaveTextValue(elementStringValue);
784 public object ValidateEndElement(XmlSchemaInfo schemaInfo) {
785 return InternalValidateEndElement(schemaInfo, null);
788 public object ValidateEndElement(XmlSchemaInfo schemaInfo, object typedValue) {
789 if (typedValue == null) {
790 throw new ArgumentNullException("typedValue");
792 if (textValue.Length > 0) {
793 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementCall));
795 return InternalValidateEndElement(schemaInfo, typedValue);
798 public void SkipToEndElement(XmlSchemaInfo schemaInfo) {
799 if (validationStack.Length <= 1) {
800 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementMultiple, MethodNames[(int)ValidatorState.SkipToEndElement]));
802 CheckStateTransition(ValidatorState.SkipToEndElement, MethodNames[(int)ValidatorState.SkipToEndElement]);
804 if (schemaInfo != null) {
805 SchemaElementDecl currentElementDecl = context.ElementDecl;
806 if (currentElementDecl != null) {
807 schemaInfo.SchemaType = currentElementDecl.SchemaType;
808 schemaInfo.SchemaElement = GetSchemaElement();
811 schemaInfo.SchemaType = null;
812 schemaInfo.SchemaElement = null;
814 schemaInfo.MemberType = null;
815 schemaInfo.IsNil = context.IsNill;
816 schemaInfo.IsDefault = context.IsDefault;
817 Debug.Assert(context.Validity != XmlSchemaValidity.Valid);
818 schemaInfo.Validity = context.Validity;
820 context.ValidationSkipped = true;
821 currentState = ValidatorState.SkipToEndElement;
825 public void EndValidation() {
826 if (validationStack.Length > 1) { //We have pending elements in the stack to call ValidateEndElement
827 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndValidation));
829 CheckStateTransition(ValidatorState.Finish, MethodNames[(int)ValidatorState.Finish]);
833 public XmlSchemaParticle[] GetExpectedParticles() {
834 if (currentState == ValidatorState.Start || currentState == ValidatorState.TopLevelTextOrWS) { //Right after initialize
835 if (partialValidationType != null) {
836 XmlSchemaElement element = partialValidationType as XmlSchemaElement;
837 if (element != null) {
838 return new XmlSchemaParticle[1] {element};
840 return EmptyParticleArray;
842 else { //Should return all global elements
843 ICollection elements = schemaSet.GlobalElements.Values;
844 ArrayList expected = new ArrayList(elements.Count);
845 foreach(XmlSchemaElement element in elements) { //Check for substitutions
846 ContentValidator.AddParticleToExpected(element, schemaSet, expected, true);
848 return expected.ToArray(typeof(XmlSchemaParticle)) as XmlSchemaParticle[];
851 if (context.ElementDecl != null) {
852 ArrayList expected = context.ElementDecl.ContentValidator.ExpectedParticles(context, false, schemaSet);
853 if (expected != null) {
854 return expected.ToArray(typeof(XmlSchemaParticle)) as XmlSchemaParticle[];
857 return EmptyParticleArray;
860 public XmlSchemaAttribute[] GetExpectedAttributes() {
861 if (currentState == ValidatorState.Element || currentState == ValidatorState.Attribute) {
862 SchemaElementDecl elementDecl = context.ElementDecl;
863 ArrayList attList = new ArrayList();
864 if (elementDecl != null) {
865 foreach(SchemaAttDef attDef in elementDecl.AttDefs.Values) {
866 if (attPresence[attDef.Name] == null) {
867 attList.Add(attDef.SchemaAttribute);
871 if (nsResolver.LookupPrefix(NsXsi) != null) { //Xsi namespace defined
872 AddXsiAttributes(attList);
874 return attList.ToArray(typeof(XmlSchemaAttribute)) as XmlSchemaAttribute[];
876 else if (currentState == ValidatorState.Start) {
877 if (partialValidationType != null) {
878 XmlSchemaAttribute attribute = partialValidationType as XmlSchemaAttribute;
879 if (attribute != null) {
880 return new XmlSchemaAttribute[1] {attribute};
884 return EmptyAttributeArray;
887 internal void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes, bool createNodeData) {
888 currentState = ValidatorState.Attribute;
889 SchemaElementDecl currentElementDecl = context.ElementDecl;
891 if (currentElementDecl != null && currentElementDecl.HasDefaultAttribute) {
892 for (int i = 0; i < currentElementDecl.DefaultAttDefs.Count; ++i) {
893 SchemaAttDef attdef = (SchemaAttDef)currentElementDecl.DefaultAttDefs[i];
894 if (!attPresence.Contains(attdef.Name)) {
895 if (attdef.DefaultValueTyped == null) { //Invalid attribute default in the schema
899 //Check to see default attributes WILL be qualified if attributeFormDefault = qualified in schema
900 string attributeNS = nameTable.Add(attdef.Name.Namespace);
901 string defaultPrefix = string.Empty;
902 if (attributeNS.Length > 0) {
903 defaultPrefix = GetDefaultAttributePrefix(attributeNS);
904 if (defaultPrefix == null || defaultPrefix.Length == 0) {
905 SendValidationEvent(Res.Sch_DefaultAttributeNotApplied, new string[2] { attdef.Name.ToString(), QNameString(context.LocalName, context.Namespace)});
909 XmlSchemaDatatype datatype = attdef.Datatype;
910 if (createNodeData) {
911 ValidatingReaderNodeData attrData = new ValidatingReaderNodeData();
912 attrData.LocalName = nameTable.Add(attdef.Name.Name);
913 attrData.Namespace = attributeNS;
914 attrData.Prefix = nameTable.Add(defaultPrefix);
915 attrData.NodeType = XmlNodeType.Attribute;
917 //set PSVI properties
918 AttributePSVIInfo attrValidInfo = new AttributePSVIInfo();
919 XmlSchemaInfo attSchemaInfo = attrValidInfo.attributeSchemaInfo;
920 Debug.Assert(attSchemaInfo != null);
921 if (attdef.Datatype.Variety == XmlSchemaDatatypeVariety.Union) {
922 XsdSimpleValue simpleValue = attdef.DefaultValueTyped as XsdSimpleValue;
923 attSchemaInfo.MemberType = simpleValue.XmlType;
924 datatype = simpleValue.XmlType.Datatype;
925 attrValidInfo.typedAttributeValue = simpleValue.TypedValue;
928 attrValidInfo.typedAttributeValue = attdef.DefaultValueTyped;
930 attSchemaInfo.IsDefault = true;
931 attSchemaInfo.Validity = XmlSchemaValidity.Valid;
932 attSchemaInfo.SchemaType = attdef.SchemaType;
933 attSchemaInfo.SchemaAttribute = attdef.SchemaAttribute;
934 attrData.RawValue = attSchemaInfo.XmlType.ValueConverter.ToString(attrValidInfo.typedAttributeValue);
936 attrData.AttInfo = attrValidInfo;
937 defaultAttributes.Add(attrData);
940 defaultAttributes.Add(attdef.SchemaAttribute);
942 CheckTokenizedTypes(datatype, attdef.DefaultValueTyped, true);
943 if (HasIdentityConstraints) {
944 AttributeIdentityConstraints(attdef.Name.Name, attdef.Name.Namespace, attdef.DefaultValueTyped, attdef.DefaultValueRaw, datatype);
952 internal XmlSchemaSet SchemaSet {
958 internal XmlSchemaValidationFlags ValidationFlags {
960 return validationFlags;
964 internal XmlSchemaContentType CurrentContentType {
966 if (context.ElementDecl == null) {
967 return XmlSchemaContentType.Empty;
969 return context.ElementDecl.ContentValidator.ContentType;
973 internal XmlSchemaContentProcessing CurrentProcessContents {
975 return processContents;
979 internal void SetDtdSchemaInfo(IDtdInfo dtdSchemaInfo) {
980 this.dtdSchemaInfo = dtdSchemaInfo;
981 this.checkEntity = true;
984 private bool StrictlyAssessed {
986 return (processContents == XmlSchemaContentProcessing.Strict || processContents == XmlSchemaContentProcessing.Lax) && context.ElementDecl != null && !context.ValidationSkipped;
990 private bool HasSchema {
994 if (!compiledSchemaInfo.Contains(context.Namespace)) {
995 rootHasSchema = false;
998 return rootHasSchema;
1002 internal string GetConcatenatedValue() {
1003 return textValue.ToString();
1006 private object InternalValidateEndElement(XmlSchemaInfo schemaInfo, object typedValue) {
1007 if (validationStack.Length <= 1) {
1008 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementMultiple, MethodNames[(int)ValidatorState.EndElement]));
1010 CheckStateTransition(ValidatorState.EndElement, MethodNames[(int)ValidatorState.EndElement]);
1012 SchemaElementDecl contextElementDecl = context.ElementDecl;
1013 XmlSchemaSimpleType memberType = null;
1014 XmlSchemaType localSchemaType = null;
1015 XmlSchemaElement localSchemaElement = null;
1017 string stringValue = string.Empty;
1019 if (contextElementDecl != null) {
1020 if (context.CheckRequiredAttribute && contextElementDecl.HasRequiredAttribute) {
1021 CheckRequiredAttributes(contextElementDecl);
1023 if (!context.IsNill) {
1024 if (context.NeedValidateChildren) {
1025 XmlSchemaContentType contentType = contextElementDecl.ContentValidator.ContentType;
1026 switch (contentType) {
1027 case XmlSchemaContentType.TextOnly:
1028 if (typedValue == null) {
1029 stringValue = textValue.ToString();
1030 typedValue = ValidateAtomicValue(stringValue, out memberType);
1032 else { //Parsed object passed in, need to verify only facets
1033 typedValue = ValidateAtomicValue(typedValue, out memberType);
1037 case XmlSchemaContentType.Mixed:
1038 if (contextElementDecl.DefaultValueTyped != null) {
1039 if (typedValue == null) {
1040 stringValue = textValue.ToString();
1041 typedValue = CheckMixedValueConstraint(stringValue);
1046 case XmlSchemaContentType.ElementOnly:
1047 if (typedValue != null) { //Cannot pass in typedValue for complex content
1048 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementCallTyped));
1055 if(!contextElementDecl.ContentValidator.CompleteValidation(context)) {
1056 CompleteValidationError(context, eventHandler, nsResolver, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition, schemaSet);
1057 context.Validity = XmlSchemaValidity.Invalid;
1061 // for each level in the stack, endchildren and fill value from element
1062 if (HasIdentityConstraints) {
1063 XmlSchemaType xmlType = memberType == null ? contextElementDecl.SchemaType : memberType;
1064 EndElementIdentityConstraints(typedValue, stringValue, xmlType.Datatype);
1066 localSchemaType = contextElementDecl.SchemaType;
1067 localSchemaElement = GetSchemaElement();
1069 if (schemaInfo != null) { //SET SchemaInfo
1070 schemaInfo.SchemaType = localSchemaType;
1071 schemaInfo.SchemaElement = localSchemaElement;
1072 schemaInfo.MemberType = memberType;
1073 schemaInfo.IsNil = context.IsNill;
1074 schemaInfo.IsDefault = context.IsDefault;
1075 if (context.Validity == XmlSchemaValidity.NotKnown && StrictlyAssessed) {
1076 context.Validity = XmlSchemaValidity.Valid;
1078 schemaInfo.Validity = context.Validity;
1084 [ResourceConsumption(ResourceScope.Machine)]
1085 [ResourceExposure(ResourceScope.Machine)]
1086 private void ProcessSchemaLocations(string xsiSchemaLocation, string xsiNoNamespaceSchemaLocation) {
1087 bool compile = false;
1088 if (xsiNoNamespaceSchemaLocation != null) {
1090 LoadSchema(string.Empty, xsiNoNamespaceSchemaLocation);
1092 if (xsiSchemaLocation != null) {
1095 Exception exception = dtStringArray.TryParseValue(xsiSchemaLocation, nameTable, nsResolver, out typedValue);
1096 if (exception != null) {
1097 SendValidationEvent(Res.Sch_InvalidValueDetailedAttribute, new string[] { "schemaLocation", xsiSchemaLocation, dtStringArray.TypeCodeString, exception.Message }, exception);
1100 string[] locations = (string[])typedValue;
1103 for (int j = 0; j < locations.Length - 1; j += 2) {
1104 LoadSchema((string)locations[j], (string)locations[j + 1]);
1107 catch (XmlSchemaException schemaException) {
1108 SendValidationEvent(schemaException);
1112 RecompileSchemaSet();
1117 private object ValidateElementContext(XmlQualifiedName elementName, out bool invalidElementInContext) {
1118 object particle = null;
1120 XmlQualifiedName head;
1121 XmlSchemaElement headElement = null;
1122 invalidElementInContext = false;
1124 if (context.NeedValidateChildren) {
1125 if (context.IsNill) {
1126 SendValidationEvent(Res.Sch_ContentInNill, QNameString(context.LocalName, context.Namespace));
1129 ContentValidator contentValidator = context.ElementDecl.ContentValidator;
1130 if (contentValidator.ContentType == XmlSchemaContentType.Mixed && context.ElementDecl.Presence == SchemaDeclBase.Use.Fixed) { //Mixed with default or fixed
1131 SendValidationEvent(Res.Sch_ElementInMixedWithFixed, QNameString(context.LocalName, context.Namespace));
1136 bool substitution = false;
1139 particle = context.ElementDecl.ContentValidator.ValidateElement(head, context, out errorCode);
1140 if (particle != null) { //Match found
1143 if (errorCode == -2) { //ContentModel all group error
1144 SendValidationEvent(Res.Sch_AllElement, elementName.ToString());
1145 invalidElementInContext = true;
1146 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1149 //Match not found; check for substitutionGroup
1150 substitution = true;
1151 headElement = GetSubstitutionGroupHead(head);
1152 if (headElement == null) {
1156 head = headElement.QualifiedName;
1161 XmlSchemaElement matchedElem = particle as XmlSchemaElement;
1162 if (matchedElem == null) { //It matched an xs:any in that position
1165 else if (matchedElem.RefName.IsEmpty) { //It is not element ref but a local element
1166 //If the head and matched particle are not hte same, then this is not substitutable, duped by a localElement with same QName
1167 SendValidationEvent(Res.Sch_InvalidElementSubstitution, BuildElementName(elementName), BuildElementName(matchedElem.QualifiedName));
1168 invalidElementInContext = true;
1169 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1171 else { //Correct substitution head found
1172 particle = compiledSchemaInfo.GetElement(elementName); //Re-assign correct particle
1173 context.NeedValidateChildren = true; //This will be reset to false once member match is not found
1176 if (particle == null) {
1177 ElementValidationError(elementName, context, eventHandler, nsResolver, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition, schemaSet);
1178 invalidElementInContext = true;
1179 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1186 private XmlSchemaElement GetSubstitutionGroupHead(XmlQualifiedName member) {
1187 XmlSchemaElement memberElem = compiledSchemaInfo.GetElement(member);
1188 if (memberElem != null) {
1189 XmlQualifiedName head = memberElem.SubstitutionGroup;
1191 XmlSchemaElement headElem = compiledSchemaInfo.GetElement(head);
1192 if (headElem != null) {
1193 if ((headElem.BlockResolved & XmlSchemaDerivationMethod.Substitution) != 0) {
1194 SendValidationEvent(Res.Sch_SubstitutionNotAllowed, new string[] {member.ToString(), head.ToString()});
1197 if (!XmlSchemaType.IsDerivedFrom(memberElem.ElementSchemaType, headElem.ElementSchemaType, headElem.BlockResolved)) {
1198 SendValidationEvent(Res.Sch_SubstitutionBlocked, new string[] {member.ToString(), head.ToString()});
1208 private object ValidateAtomicValue(string stringValue, out XmlSchemaSimpleType memberType) {
1209 object typedVal = null;
1211 SchemaElementDecl currentElementDecl = context.ElementDecl;
1212 if (!context.IsNill) {
1213 if (stringValue.Length == 0 && currentElementDecl.DefaultValueTyped != null) { //default value maybe present
1214 SchemaElementDecl declBeforeXsi = context.ElementDeclBeforeXsi;
1215 if (declBeforeXsi != null && declBeforeXsi != currentElementDecl) { //There was xsi:type
1216 Debug.Assert(currentElementDecl.Datatype != null);
1217 Exception exception = currentElementDecl.Datatype.TryParseValue(currentElementDecl.DefaultValueRaw, nameTable, nsResolver, out typedVal);
1218 if (exception != null) {
1219 SendValidationEvent(Res.Sch_InvalidElementDefaultValue, new string[] { currentElementDecl.DefaultValueRaw, QNameString(context.LocalName, context.Namespace) });
1222 context.IsDefault = true;
1226 context.IsDefault = true;
1227 typedVal = currentElementDecl.DefaultValueTyped;
1231 typedVal = CheckElementValue(stringValue);
1233 XsdSimpleValue simpleValue = typedVal as XsdSimpleValue;
1234 XmlSchemaDatatype dtype = currentElementDecl.Datatype;
1235 if (simpleValue != null) {
1236 memberType = simpleValue.XmlType;
1237 typedVal = simpleValue.TypedValue;
1238 dtype = memberType.Datatype;
1240 CheckTokenizedTypes(dtype, typedVal, false);
1245 private object ValidateAtomicValue(object parsedValue, out XmlSchemaSimpleType memberType) {
1247 SchemaElementDecl currentElementDecl = context.ElementDecl;
1248 object typedValue = null;
1249 if (!context.IsNill) {
1250 SchemaDeclBase decl = currentElementDecl as SchemaDeclBase;
1251 XmlSchemaDatatype dtype = currentElementDecl.Datatype;
1252 Exception exception = dtype.TryParseValue(parsedValue, nameTable, nsResolver, out typedValue);
1253 if (exception != null) {
1254 string stringValue = parsedValue as string;
1255 if (stringValue == null) {
1256 stringValue = XmlSchemaDatatype.ConcatenatedToString(parsedValue);
1258 SendValidationEvent(Res.Sch_ElementValueDataTypeDetailed, new string[] { QNameString(context.LocalName, context.Namespace), stringValue, GetTypeName(decl), exception.Message }, exception);
1261 if (!decl.CheckValue(typedValue)) {
1262 SendValidationEvent(Res.Sch_FixedElementValue, QNameString(context.LocalName, context.Namespace));
1264 if (dtype.Variety == XmlSchemaDatatypeVariety.Union) {
1265 XsdSimpleValue simpleValue = typedValue as XsdSimpleValue;
1266 Debug.Assert(simpleValue != null);
1267 memberType = simpleValue.XmlType;
1268 typedValue = simpleValue.TypedValue;
1269 dtype = memberType.Datatype;
1271 CheckTokenizedTypes(dtype, typedValue, false);
1276 private string GetTypeName(SchemaDeclBase decl) {
1277 Debug.Assert(decl != null && decl.SchemaType != null);
1278 string typeName = decl.SchemaType.QualifiedName.ToString();
1279 if (typeName.Length == 0) {
1280 typeName = decl.Datatype.TypeCodeString;
1285 private void SaveTextValue(object value) {
1286 string s = value.ToString(); //For strings, which will mostly be the case, ToString() will return this. For other typedValues, need to go through value converter (eg: TimeSpan, DateTime etc)
1287 textValue.Append(s);
1290 private void Push(XmlQualifiedName elementName) {
1291 context = (ValidationState)validationStack.Push();
1292 if (context == null) {
1293 context = new ValidationState();
1294 validationStack.AddToTop(context);
1296 context.LocalName = elementName.Name;
1297 context.Namespace = elementName.Namespace;
1298 context.HasMatched = false;
1299 context.IsNill = false;
1300 context.IsDefault = false;
1301 context.CheckRequiredAttribute = true;
1302 context.ValidationSkipped = false;
1303 context.Validity = XmlSchemaValidity.NotKnown;
1304 context.NeedValidateChildren = false;
1305 context.ProcessContents = processContents;
1306 context.ElementDeclBeforeXsi = null;
1307 context.Constr = null; //resetting the constraints to be null incase context != null
1308 // when pushing onto stack;
1311 private void Pop() {
1312 Debug.Assert(validationStack.Length > 1);
1313 ValidationState previousContext = (ValidationState)validationStack.Pop();
1315 if (startIDConstraint == validationStack.Length) {
1316 startIDConstraint = -1;
1318 context = (ValidationState)validationStack.Peek();
1319 if (previousContext.Validity == XmlSchemaValidity.Invalid) { //Should set current context's validity to that of what was popped now in case of Invalid
1320 context.Validity = XmlSchemaValidity.Invalid;
1322 if (previousContext.ValidationSkipped) {
1323 context.ValidationSkipped = true;
1325 processContents = context.ProcessContents;
1328 private void AddXsiAttributes(ArrayList attList) {
1329 BuildXsiAttributes();
1330 if (attPresence[xsiTypeSO.QualifiedName] == null) {
1331 attList.Add(xsiTypeSO);
1333 if (attPresence[xsiNilSO.QualifiedName] == null) {
1334 attList.Add(xsiNilSO);
1336 if (attPresence[xsiSLSO.QualifiedName] == null) {
1337 attList.Add(xsiSLSO);
1339 if (attPresence[xsiNoNsSLSO.QualifiedName] == null) {
1340 attList.Add(xsiNoNsSLSO);
1344 private SchemaElementDecl FastGetElementDecl(XmlQualifiedName elementName, object particle) {
1345 SchemaElementDecl elementDecl = null;
1346 if (particle != null) {
1347 XmlSchemaElement element = particle as XmlSchemaElement;
1348 if (element != null) {
1349 elementDecl = element.ElementDecl;
1352 XmlSchemaAny any = (XmlSchemaAny)particle;
1353 processContents = any.ProcessContentsCorrect;
1356 if (elementDecl == null && processContents != XmlSchemaContentProcessing.Skip) {
1357 if (isRoot && partialValidationType != null) {
1358 if (partialValidationType is XmlSchemaElement) {
1359 XmlSchemaElement element = (XmlSchemaElement)partialValidationType;
1360 if (elementName.Equals(element.QualifiedName)) {
1361 elementDecl = element.ElementDecl;
1364 SendValidationEvent(Res.Sch_SchemaElementNameMismatch, elementName.ToString(), element.QualifiedName.ToString());
1367 else if (partialValidationType is XmlSchemaType) { //Element name is wildcard
1368 XmlSchemaType type = (XmlSchemaType)partialValidationType;
1369 elementDecl = type.ElementDecl;
1371 else { //its XmlSchemaAttribute
1372 Debug.Assert(partialValidationType is XmlSchemaAttribute);
1373 SendValidationEvent(Res.Sch_ValidateElementInvalidCall, string.Empty);
1377 elementDecl = compiledSchemaInfo.GetElementDecl(elementName);
1383 private SchemaElementDecl CheckXsiTypeAndNil(SchemaElementDecl elementDecl, string xsiType, string xsiNil, ref bool declFound) {
1384 XmlQualifiedName xsiTypeName = XmlQualifiedName.Empty;
1385 if (xsiType != null) {
1386 object typedVal = null;
1387 Exception exception = dtQName.TryParseValue(xsiType, nameTable, nsResolver, out typedVal);
1388 if (exception != null) {
1389 SendValidationEvent(Res.Sch_InvalidValueDetailedAttribute, new string[] { "type", xsiType, dtQName.TypeCodeString, exception.Message }, exception);
1392 xsiTypeName = typedVal as XmlQualifiedName;
1395 if (elementDecl != null) { //nillable is not dependent on xsi:type.
1396 if (elementDecl.IsNillable) {
1397 if (xsiNil != null) {
1398 context.IsNill = XmlConvert.ToBoolean(xsiNil);
1399 if (context.IsNill && elementDecl.Presence == SchemaDeclBase.Use.Fixed) {
1400 Debug.Assert(elementDecl.DefaultValueTyped != null);
1401 SendValidationEvent(Res.Sch_XsiNilAndFixed);
1405 else if (xsiNil != null) {
1406 SendValidationEvent(Res.Sch_InvalidXsiNill);
1409 if (xsiTypeName.IsEmpty) {
1410 if (elementDecl != null && elementDecl.IsAbstract) {
1411 SendValidationEvent(Res.Sch_AbstractElement, QNameString(context.LocalName, context.Namespace));
1416 SchemaElementDecl elementDeclXsi = compiledSchemaInfo.GetTypeDecl(xsiTypeName);
1417 XmlSeverityType severity = XmlSeverityType.Warning;
1418 if (HasSchema && processContents == XmlSchemaContentProcessing.Strict) {
1419 severity = XmlSeverityType.Error;
1421 if (elementDeclXsi == null && xsiTypeName.Namespace == NsXs) {
1422 XmlSchemaType schemaType = DatatypeImplementation.GetSimpleTypeFromXsdType(xsiTypeName);
1423 if (schemaType == null) { //try getting complexType - xs:anyType
1424 schemaType = XmlSchemaType.GetBuiltInComplexType(xsiTypeName);
1426 if (schemaType != null) {
1427 elementDeclXsi = schemaType.ElementDecl;
1431 if (elementDeclXsi == null) {
1432 SendValidationEvent(Res.Sch_XsiTypeNotFound, xsiTypeName.ToString(), severity);
1437 if (elementDeclXsi.IsAbstract) {
1438 SendValidationEvent(Res.Sch_XsiTypeAbstract, xsiTypeName.ToString(), severity);
1441 else if (elementDecl != null && !XmlSchemaType.IsDerivedFrom(elementDeclXsi.SchemaType,elementDecl.SchemaType,elementDecl.Block)) {
1442 SendValidationEvent(Res.Sch_XsiTypeBlockedEx, new string[] { xsiTypeName.ToString(), QNameString(context.LocalName, context.Namespace) });
1446 if (elementDecl != null) { //Get all element decl properties before assigning xsi:type decl; nillable already checked
1447 elementDeclXsi = elementDeclXsi.Clone(); //Before updating properties onto xsi:type decl, clone it
1448 elementDeclXsi.Constraints = elementDecl.Constraints;
1449 elementDeclXsi.DefaultValueRaw = elementDecl.DefaultValueRaw;
1450 elementDeclXsi.DefaultValueTyped = elementDecl.DefaultValueTyped;
1451 elementDeclXsi.Block = elementDecl.Block;
1453 context.ElementDeclBeforeXsi = elementDecl;
1454 elementDecl = elementDeclXsi;
1461 private void ThrowDeclNotFoundWarningOrError(bool declFound) {
1462 if (declFound) { //But invalid, so discontinue processing of children
1463 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1464 context.NeedValidateChildren = false;
1466 else if (HasSchema && processContents == XmlSchemaContentProcessing.Strict) { //Error and skip validation for children
1467 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1468 context.NeedValidateChildren = false;
1469 SendValidationEvent(Res.Sch_UndeclaredElement, QNameString(context.LocalName, context.Namespace));
1472 SendValidationEvent(Res.Sch_NoElementSchemaFound, QNameString(context.LocalName, context.Namespace), XmlSeverityType.Warning);
1476 private void CheckElementProperties () {
1477 if (context.ElementDecl.IsAbstract) {
1478 SendValidationEvent(Res.Sch_AbstractElement, QNameString(context.LocalName, context.Namespace));
1482 private void ValidateStartElementIdentityConstraints() {
1483 // added on June 15, set the context here, so the stack can have them
1484 if (ProcessIdentityConstraints && context.ElementDecl.Constraints != null) {
1485 AddIdentityConstraints();
1487 //foreach constraint in stack (including the current one)
1488 if (HasIdentityConstraints) {
1489 ElementIdentityConstraints();
1493 private SchemaAttDef CheckIsXmlAttribute(XmlQualifiedName attQName) {
1494 SchemaAttDef attdef = null;
1495 if (Ref.Equal(attQName.Namespace, NsXml) && (validationFlags & XmlSchemaValidationFlags.AllowXmlAttributes) != 0) { //Need to check if this attribute is an xml attribute
1496 if (!compiledSchemaInfo.Contains(NsXml)) { //We dont have a schema for xml namespace
1497 // It can happen that the schemaSet already contains the schema for xml namespace
1498 // and we just have a stale compiled schema info (for example if the same schema set is used
1499 // by two validators at the same time and the one before us added the xml namespace schema
1500 // via this code here)
1501 // In that case it is actually OK to try to add the schema for xml namespace again
1502 // since we're adding the exact same instance (the built in xml namespace schema is a singleton)
1503 // The addition on the schemaset is an effective no-op plus it's thread safe, so it's better to leave
1504 // that up to the schema set. The result of the below call will be simply that we update the
1505 // reference to the comipledSchemaInfo - which is exactly what we want in that case.
1506 // In theory it can actually happen that there is some other schema registered for the xml namespace
1507 // (other than our built in one), and we don't know about it. In that case we don't support such scenario
1508 // as the user is modifying the schemaset as we're using it, which we don't support
1509 // for bunch of other reasons, so trying to add our built-in schema won't make it worse.
1510 AddXmlNamespaceSchema();
1512 compiledSchemaInfo.AttributeDecls.TryGetValue(attQName, out attdef); //the xml attributes are all global attributes
1517 private void AddXmlNamespaceSchema() {
1518 XmlSchemaSet localSet = new XmlSchemaSet(); //Avoiding cost of incremental compilation checks by compiling schema in a seperate set and adding compiled set
1519 localSet.Add(Preprocessor.GetBuildInSchema());
1521 schemaSet.Add(localSet);
1522 RecompileSchemaSet();
1525 internal object CheckMixedValueConstraint(string elementValue) {
1526 SchemaElementDecl elementDecl = context.ElementDecl;
1527 Debug.Assert(elementDecl.ContentValidator.ContentType == XmlSchemaContentType.Mixed && elementDecl.DefaultValueTyped != null);
1528 if (context.IsNill) { //Nil and fixed is error; Nil and default is compile time error
1531 if (elementValue.Length == 0) {
1532 context.IsDefault = true;
1533 return elementDecl.DefaultValueTyped;
1536 SchemaDeclBase decl = elementDecl as SchemaDeclBase;
1537 Debug.Assert(decl != null);
1538 if (decl.Presence == SchemaDeclBase.Use.Fixed && !elementValue.Equals(elementDecl.DefaultValueRaw)) { //check string equality for mixed as it is untyped.
1539 SendValidationEvent(Res.Sch_FixedElementValue, elementDecl.Name.ToString());
1541 return elementValue;
1545 [ResourceConsumption(ResourceScope.Machine)]
1546 [ResourceExposure(ResourceScope.Machine)]
1547 private void LoadSchema(string uri, string url) {
1548 Debug.Assert(xmlResolver != null);
1549 XmlReader Reader = null;
1551 Uri ruri = xmlResolver.ResolveUri(sourceUri, url);
1552 Stream stm = (Stream)xmlResolver.GetEntity(ruri,null,null);
1553 XmlReaderSettings readerSettings = schemaSet.ReaderSettings;
1554 readerSettings.CloseInput = true;
1555 readerSettings.XmlResolver = xmlResolver;
1556 Reader = XmlReader.Create(stm, readerSettings, ruri.ToString());
1557 schemaSet.Add(uri, Reader, validatedNamespaces);
1558 while(Reader.Read());// wellformness check
1560 catch(XmlSchemaException e) {
1561 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, e);
1563 catch(Exception e) {
1564 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, e, XmlSeverityType.Warning);
1567 if (Reader != null) {
1574 internal void RecompileSchemaSet() {
1575 if (!schemaSet.IsCompiled) {
1577 schemaSet.Compile();
1579 catch(XmlSchemaException e) {
1580 SendValidationEvent(e);
1583 compiledSchemaInfo = schemaSet.CompiledInfo; //Fetch compiled info from set
1586 private void ProcessTokenizedType(XmlTokenizedType ttype, string name, bool attrValue) {
1588 case XmlTokenizedType.ID:
1589 if (ProcessIdentityConstraints) {
1590 if (FindId(name) != null) {
1594 SendValidationEvent(Res.Sch_DupId, name);
1597 if (IDs == null) { //ADD ID
1598 IDs = new Hashtable();
1600 IDs.Add(name, context.LocalName);
1604 case XmlTokenizedType.IDREF:
1605 if (ProcessIdentityConstraints) {
1606 object p = FindId(name);
1607 if (p == null) { // add it to linked list to check it later
1608 idRefListHead = new IdRefNode(idRefListHead, name, positionInfo.LineNumber, positionInfo.LinePosition);
1612 case XmlTokenizedType.ENTITY:
1613 ProcessEntity(name);
1620 private object CheckAttributeValue(object value, SchemaAttDef attdef) {
1621 object typedValue = null;
1622 SchemaDeclBase decl = attdef as SchemaDeclBase;
1624 XmlSchemaDatatype dtype = attdef.Datatype;
1625 Debug.Assert(dtype != null);
1626 string stringValue = value as string;
1627 Exception exception = null;
1629 if (stringValue != null) { //
1630 exception = dtype.TryParseValue(stringValue, nameTable, nsResolver, out typedValue);
1631 if (exception != null) goto Error;
1633 else { //Calling object ParseValue for checking facets
1634 exception = dtype.TryParseValue(value, nameTable, nsResolver, out typedValue);
1635 if (exception != null) goto Error;
1637 if (!decl.CheckValue(typedValue)) {
1639 SendValidationEvent(Res.Sch_FixedAttributeValue, attdef.Name.ToString());
1645 if (stringValue == null) {
1646 stringValue = XmlSchemaDatatype.ConcatenatedToString(value);
1648 SendValidationEvent(Res.Sch_AttributeValueDataTypeDetailed, new string[] { attdef.Name.ToString(), stringValue, GetTypeName(decl), exception.Message }, exception);
1652 private object CheckElementValue(string stringValue) {
1653 object typedValue = null;
1654 SchemaDeclBase decl = context.ElementDecl as SchemaDeclBase;
1656 XmlSchemaDatatype dtype = decl.Datatype;
1657 Debug.Assert(dtype != null);
1659 Exception exception = dtype.TryParseValue(stringValue, nameTable, nsResolver, out typedValue);
1660 if (exception != null) {
1661 SendValidationEvent(Res.Sch_ElementValueDataTypeDetailed, new string[] { QNameString(context.LocalName, context.Namespace), stringValue, GetTypeName(decl), exception.Message }, exception);
1664 if (!decl.CheckValue(typedValue)) {
1665 SendValidationEvent(Res.Sch_FixedElementValue, QNameString(context.LocalName, context.Namespace));
1670 private void CheckTokenizedTypes(XmlSchemaDatatype dtype, object typedValue, bool attrValue) {
1671 // Check special types
1672 if (typedValue == null) {
1675 XmlTokenizedType ttype = dtype.TokenizedType;
1676 if (ttype == XmlTokenizedType.ENTITY || ttype == XmlTokenizedType.ID || ttype == XmlTokenizedType.IDREF) {
1677 if (dtype.Variety == XmlSchemaDatatypeVariety.List) {
1678 string[] ss = (string[])typedValue;
1679 for (int i = 0; i < ss.Length; ++i) {
1680 ProcessTokenizedType(dtype.TokenizedType, ss[i], attrValue);
1684 ProcessTokenizedType(dtype.TokenizedType, (string)typedValue, attrValue);
1689 private object FindId(string name) {
1690 return IDs == null ? null : IDs[name];
1693 private void CheckForwardRefs() {
1694 IdRefNode next = idRefListHead;
1695 while (next != null) {
1696 if(FindId(next.Id) == null) {
1697 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_UndeclaredId, next.Id, this.sourceUriString, next.LineNo, next.LinePos), XmlSeverityType.Error);
1699 IdRefNode ptr = next.Next;
1700 next.Next = null; // unhook each object so it is cleaned up by Garbage Collector
1703 // not needed any more.
1704 idRefListHead = null;
1708 private bool HasIdentityConstraints {
1709 get { return ProcessIdentityConstraints && startIDConstraint != -1; }
1712 internal bool ProcessIdentityConstraints {
1714 return (validationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) != 0;
1718 internal bool ReportValidationWarnings {
1720 return (validationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) != 0;
1724 internal bool ProcessInlineSchema {
1726 return (validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0;
1730 internal bool ProcessSchemaLocation {
1732 return (validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0;
1736 internal bool ProcessSchemaHints {
1738 return (validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0 ||
1739 (validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0;
1743 private void CheckStateTransition(ValidatorState toState, string methodName) {
1744 if (!ValidStates[(int)currentState,(int)toState]) {
1745 if (currentState == ValidatorState.None) {
1746 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStartTransition, new string[] { methodName, MethodNames[(int)ValidatorState.Start] }));
1748 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStateTransition, new string[] { MethodNames[(int)currentState], methodName }));
1750 currentState = toState;
1753 private void ClearPSVI() {
1754 if (textValue != null) {
1755 textValue.Length = 0;
1757 attPresence.Clear(); //Clear attributes hashtable for every element
1758 wildID = null; //clear it for every element
1761 private void CheckRequiredAttributes(SchemaElementDecl currentElementDecl) {
1762 Debug.Assert(currentElementDecl != null);
1763 Dictionary<XmlQualifiedName, SchemaAttDef> attributeDefs = currentElementDecl.AttDefs;
1764 foreach(SchemaAttDef attdef in attributeDefs.Values) {
1765 if (attPresence[attdef.Name] == null) {
1766 if (attdef.Presence == SchemaDeclBase.Use.Required || attdef.Presence == SchemaDeclBase.Use.RequiredFixed) {
1767 SendValidationEvent(Res.Sch_MissRequiredAttribute, attdef.Name.ToString());
1773 private XmlSchemaElement GetSchemaElement() {
1774 SchemaElementDecl beforeXsiDecl = context.ElementDeclBeforeXsi;
1775 SchemaElementDecl currentDecl = context.ElementDecl;
1777 if (beforeXsiDecl != null) { //Have a xsi:type
1778 if (beforeXsiDecl.SchemaElement != null) {
1779 XmlSchemaElement xsiElement = (XmlSchemaElement)beforeXsiDecl.SchemaElement.Clone(null);
1780 xsiElement.SchemaTypeName = XmlQualifiedName.Empty; //Reset typeName on element as this might be different
1781 xsiElement.SchemaType = currentDecl.SchemaType;
1782 xsiElement.SetElementType(currentDecl.SchemaType);
1783 xsiElement.ElementDecl = currentDecl;
1787 return currentDecl.SchemaElement;
1790 internal string GetDefaultAttributePrefix(string attributeNS) {
1791 IDictionary<string,string> namespaceDecls = nsResolver.GetNamespacesInScope(XmlNamespaceScope.All);
1792 string defaultPrefix = null;
1795 foreach (KeyValuePair<string,string> pair in namespaceDecls) {
1796 defaultNS = nameTable.Add(pair.Value);
1797 if (Ref.Equal(defaultNS, attributeNS)) {
1798 defaultPrefix = pair.Key;
1799 if (defaultPrefix.Length != 0) { //Locate first non-empty prefix
1800 return defaultPrefix;
1804 return defaultPrefix;
1807 private void AddIdentityConstraints() {
1808 SchemaElementDecl currentElementDecl = context.ElementDecl;
1809 context.Constr = new ConstraintStruct[currentElementDecl.Constraints.Length];
1811 for (int i = 0; i < currentElementDecl.Constraints.Length; ++i)
1813 context.Constr[id++] = new ConstraintStruct(currentElementDecl.Constraints[i]);
1814 } // foreach constraint /constraintstruct
1816 // added on June 19, make connections between new keyref tables with key/unique tables in stack
1817 // i can't put it in the above loop, coz there will be key on the same level
1818 for (int i = 0; i < context.Constr.Length; ++i) {
1819 if ( context.Constr[i].constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref ) {
1821 // go upwards checking or only in this level
1822 for (int level = this.validationStack.Length - 1; level >= ((this.startIDConstraint >= 0) ? this.startIDConstraint : this.validationStack.Length - 1); level --) {
1823 // no constraint for this level
1824 if (((ValidationState)(this.validationStack[level])).Constr == null) {
1828 ConstraintStruct[] constraintStructures = ((ValidationState)this.validationStack[level]).Constr;
1829 for (int j = 0; j < constraintStructures.Length; ++j) {
1830 if (constraintStructures[j].constraint.name == context.Constr[i].constraint.refer) {
1832 if (constraintStructures[j].keyrefTable == null) {
1833 constraintStructures[j].keyrefTable = new Hashtable();
1835 context.Constr[i].qualifiedTable = constraintStructures[j].keyrefTable;
1845 // didn't find connections, throw exceptions
1846 SendValidationEvent(Res.Sch_RefNotInScope, QNameString(context.LocalName, context.Namespace));
1848 } // finished dealing with keyref
1853 if (this.startIDConstraint == -1) {
1854 this.startIDConstraint = this.validationStack.Length - 1;
1858 private void ElementIdentityConstraints () {
1859 SchemaElementDecl currentElementDecl = context.ElementDecl;
1860 string localName = context.LocalName;
1861 string namespaceUri = context.Namespace;
1863 for (int i = this.startIDConstraint; i < this.validationStack.Length; i ++) {
1864 // no constraint for this level
1865 if (((ValidationState)(this.validationStack[i])).Constr == null) {
1870 ConstraintStruct[] constraintStructures = ((ValidationState)this.validationStack[i]).Constr;
1871 for (int j = 0; j < constraintStructures.Length; ++j) {
1872 // check selector from here
1873 if (constraintStructures[j].axisSelector.MoveToStartElement(localName, namespaceUri)) {
1874 // selector selects new node, activate a new set of fields
1875 Debug.WriteLine("Selector Match!");
1876 Debug.WriteLine("Name: " + localName + "\t|\tURI: " + namespaceUri + "\n");
1878 // in which axisFields got updated
1879 constraintStructures[j].axisSelector.PushKS(positionInfo.LineNumber, positionInfo.LinePosition);
1882 // axisFields is not null, but may be empty
1883 for (int k = 0; k < constraintStructures[j].axisFields.Count; ++k) {
1884 LocatedActiveAxis laxis = (LocatedActiveAxis)constraintStructures[j].axisFields[k];
1886 // check field from here
1887 if (laxis.MoveToStartElement(localName, namespaceUri)) {
1888 Debug.WriteLine("Element Field Match!");
1889 // checking simpleType / simpleContent
1890 if (currentElementDecl != null) { // nextElement can be null when xml/xsd are not valid
1891 if (currentElementDecl.Datatype == null || currentElementDecl.ContentValidator.ContentType == XmlSchemaContentType.Mixed) {
1892 SendValidationEvent(Res.Sch_FieldSimpleTypeExpected, localName);
1895 // can't fill value here, wait till later....
1896 // fill type : xsdType
1897 laxis.isMatched = true;
1898 // since it's simpletyped element, the endchildren will come consequently... don't worry
1907 private void AttributeIdentityConstraints(string name, string ns, object obj, string sobj, XmlSchemaDatatype datatype) {
1908 for (int ci = this.startIDConstraint; ci < this.validationStack.Length; ci ++) {
1909 // no constraint for this level
1910 if (((ValidationState)(this.validationStack[ci])).Constr == null) {
1915 ConstraintStruct[] constraintStructures = ((ValidationState)this.validationStack[ci]).Constr;
1916 for (int i = 0; i < constraintStructures.Length; ++i) {
1917 // axisFields is not null, but may be empty
1918 for (int j = 0; j < constraintStructures[i].axisFields.Count; ++j) {
1919 LocatedActiveAxis laxis = (LocatedActiveAxis)constraintStructures[i].axisFields[j];
1921 // check field from here
1922 if (laxis.MoveToAttribute(name, ns)) {
1923 Debug.WriteLine("Attribute Field Match!");
1924 //attribute is only simpletype, so needn't checking...
1925 // can fill value here, yeah!!
1926 Debug.WriteLine("Attribute Field Filling Value!");
1927 Debug.WriteLine("Name: " + name + "\t|\tURI: " + ns + "\t|\tValue: " + obj + "\n");
1928 if (laxis.Ks[laxis.Column] != null) {
1929 // should be evaluated to either an empty node-set or a node-set with exactly one member
1931 SendValidationEvent (Res.Sch_FieldSingleValueExpected, name);
1934 Debug.Assert(datatype != null);
1935 laxis.Ks[laxis.Column] = new TypedObject (obj, sobj, datatype);
1943 private void EndElementIdentityConstraints(object typedValue, string stringValue, XmlSchemaDatatype datatype) {
1944 string localName = context.LocalName;
1945 string namespaceUri = context.Namespace;
1946 for (int ci = this.validationStack.Length - 1; ci >= this.startIDConstraint; ci --) {
1947 // no constraint for this level
1948 if (((ValidationState)(this.validationStack[ci])).Constr == null) {
1953 ConstraintStruct[] constraints = ((ValidationState)this.validationStack[ci]).Constr;
1954 for (int i = 0; i < constraints.Length; ++i) {
1956 // axisFields is not null, but may be empty
1957 for (int j = 0; j < constraints[i].axisFields.Count; ++j) {
1958 LocatedActiveAxis laxis = (LocatedActiveAxis)constraints[i].axisFields[j];
1960 // check field from here
1961 // isMatched is false when nextElement is null. so needn't change this part.
1962 if (laxis.isMatched) {
1963 Debug.WriteLine("Element Field Filling Value!");
1964 Debug.WriteLine("Name: " + localName + "\t|\tURI: " + namespaceUri + "\t|\tValue: " + typedValue + "\n");
1966 laxis.isMatched = false;
1967 if (laxis.Ks[laxis.Column] != null) {
1968 // [field...] should be evaluated to either an empty node-set or a node-set with exactly one member
1969 // two matches... already existing field value in the table.
1970 SendValidationEvent (Res.Sch_FieldSingleValueExpected, localName);
1973 // for element, Reader.Value = "";
1974 if(typedValue != null && stringValue.Length != 0) {
1975 laxis.Ks[laxis.Column] = new TypedObject(typedValue, stringValue, datatype);
1980 laxis.EndElement(localName, namespaceUri);
1983 if (constraints[i].axisSelector.EndElement(localName, namespaceUri)) {
1984 // insert key sequence into hash (+ located active axis tuple leave for later)
1985 KeySequence ks = constraints[i].axisSelector.PopKS();
1986 // unqualified keysequence are not allowed
1987 switch (constraints[i].constraint.Role) {
1988 case CompiledIdentityConstraint.ConstraintRole.Key:
1989 if (! ks.IsQualified()) {
1990 //Key's fields can't be null... if we can return context node's line info maybe it will be better
1991 //only keymissing & keyduplicate reporting cases are necessary to be dealt with... 3 places...
1992 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_MissingKey, constraints[i].constraint.name.ToString(), sourceUriString, ks.PosLine, ks.PosCol));
1994 else if (constraints[i].qualifiedTable.Contains (ks)) {
1995 // unique or key checking value confliction
1996 // for redundant key, reporting both occurings
1997 // doesn't work... how can i retrieve value out??
1998 // KeySequence ks2 = (KeySequence) conuct.qualifiedTable[ks];
1999 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_DuplicateKey,
2000 new string[2] {ks.ToString(), constraints[i].constraint.name.ToString()},
2001 sourceUriString, ks.PosLine, ks.PosCol));
2004 constraints[i].qualifiedTable.Add (ks, ks);
2008 case CompiledIdentityConstraint.ConstraintRole.Unique:
2009 if (LocalAppContextSwitches.IgnoreEmptyKeySequences) {
2010 if (!ks.IsQualified()) {
2014 if (constraints[i].qualifiedTable.Contains (ks)) {
2015 // unique or key checking confliction
2016 // KeySequence ks2 = (KeySequence) conuct.qualifiedTable[ks];
2017 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_DuplicateKey,
2018 new string[2] {ks.ToString(), constraints[i].constraint.name.ToString()},
2019 sourceUriString, ks.PosLine, ks.PosCol));
2022 constraints[i].qualifiedTable.Add (ks, ks);
2025 case CompiledIdentityConstraint.ConstraintRole.Keyref:
2026 // is there any possibility:
2027 // 2 keyrefs: value is equal, type is not
2028 // both put in the hashtable, 1 reference, 1 not
2029 if (constraints[i].qualifiedTable != null) { //Will be null in cases when the keyref is outside the scope of the key, that is not allowed by our impl
2030 if (! ks.IsQualified() || constraints[i].qualifiedTable.Contains (ks)) {
2033 constraints[i].qualifiedTable.Add (ks, ks);
2042 // current level's constraint struct
2043 ConstraintStruct[] vcs = ((ValidationState)(this.validationStack[this.validationStack.Length - 1])).Constr;
2045 // validating all referencing tables...
2047 for (int i = 0; i < vcs.Length; ++i) {
2048 if (( vcs[i].constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref)
2049 || (vcs[i].keyrefTable == null)) {
2052 foreach (KeySequence ks in vcs[i].keyrefTable.Keys) {
2053 if (!vcs[i].qualifiedTable.Contains(ks)) {
2054 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_UnresolvedKeyref, new string[2] { ks.ToString(), vcs[i].constraint.name.ToString() },
2055 sourceUriString, ks.PosLine, ks.PosCol));
2063 private static void BuildXsiAttributes() {
2064 if (xsiTypeSO == null) { //xsi:type attribute
2065 XmlSchemaAttribute tempXsiTypeSO = new XmlSchemaAttribute();
2066 tempXsiTypeSO.Name = "type";
2067 tempXsiTypeSO.SetQualifiedName(new XmlQualifiedName("type", XmlReservedNs.NsXsi));
2068 tempXsiTypeSO.SetAttributeType(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.QName));
2069 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiTypeSO, tempXsiTypeSO, null);
2071 if (xsiNilSO == null) { //xsi:nil
2072 XmlSchemaAttribute tempxsiNilSO = new XmlSchemaAttribute();
2073 tempxsiNilSO.Name = "nil";
2074 tempxsiNilSO.SetQualifiedName(new XmlQualifiedName("nil", XmlReservedNs.NsXsi));
2075 tempxsiNilSO.SetAttributeType(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean));
2076 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiNilSO, tempxsiNilSO, null);
2078 if (xsiSLSO == null) { //xsi:schemaLocation
2079 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String);
2080 XmlSchemaAttribute tempxsiSLSO = new XmlSchemaAttribute();
2081 tempxsiSLSO.Name = "schemaLocation";
2082 tempxsiSLSO.SetQualifiedName(new XmlQualifiedName("schemaLocation", XmlReservedNs.NsXsi));
2083 tempxsiSLSO.SetAttributeType(stringType);
2084 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiSLSO, tempxsiSLSO, null);
2086 if (xsiNoNsSLSO == null) {
2087 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String);
2088 XmlSchemaAttribute tempxsiNoNsSLSO = new XmlSchemaAttribute();
2089 tempxsiNoNsSLSO.Name = "noNamespaceSchemaLocation";
2090 tempxsiNoNsSLSO.SetQualifiedName(new XmlQualifiedName("noNamespaceSchemaLocation", XmlReservedNs.NsXsi));
2091 tempxsiNoNsSLSO.SetAttributeType(stringType);
2092 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiNoNsSLSO, tempxsiNoNsSLSO, null);
2096 internal static void ElementValidationError(XmlQualifiedName name, ValidationState context, ValidationEventHandler eventHandler, object sender, string sourceUri, int lineNo, int linePos, XmlSchemaSet schemaSet) {
2097 ArrayList names = null;
2098 if (context.ElementDecl != null) {
2099 ContentValidator contentValidator = context.ElementDecl.ContentValidator;
2100 XmlSchemaContentType contentType = contentValidator.ContentType;
2101 if (contentType == XmlSchemaContentType.ElementOnly || (contentType == XmlSchemaContentType.Mixed && contentValidator != ContentValidator.Mixed && contentValidator != ContentValidator.Any)) {
2102 Debug.Assert(contentValidator is DfaContentValidator || contentValidator is NfaContentValidator || contentValidator is RangeContentValidator || contentValidator is AllElementsContentValidator);
2103 bool getParticles = schemaSet != null;
2105 names = contentValidator.ExpectedParticles(context, false, schemaSet);
2108 names = contentValidator.ExpectedElements(context, false);
2111 if (names == null || names.Count == 0) {
2112 if (context.TooComplex) {
2113 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContentComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2116 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContent, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2120 Debug.Assert(names.Count > 0);
2121 if (context.TooComplex) {
2122 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContentExpectingComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name), PrintExpectedElements(names, getParticles), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2125 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContentExpecting, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name), PrintExpectedElements(names, getParticles) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2129 else { //Base ContentValidator: Empty || TextOnly || Mixed || Any
2130 if (contentType == XmlSchemaContentType.Empty) {
2131 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementInEmptyEx, new string[] { QNameString(context.LocalName, context.Namespace), name.ToString() }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2133 else if (!contentValidator.IsOpen) {
2134 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementInTextOnlyEx, new string[] { QNameString(context.LocalName, context.Namespace), name.ToString() }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2140 internal static void CompleteValidationError(ValidationState context, ValidationEventHandler eventHandler, object sender, string sourceUri, int lineNo, int linePos, XmlSchemaSet schemaSet)
2142 ArrayList names = null;
2143 bool getParticles = schemaSet != null;
2144 if (context.ElementDecl != null) {
2146 names = context.ElementDecl.ContentValidator.ExpectedParticles(context, true, schemaSet);
2149 names = context.ElementDecl.ContentValidator.ExpectedElements(context, true);
2152 if (names == null || names.Count == 0) {
2153 if (context.TooComplex) {
2154 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContentComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2156 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContent, BuildElementName(context.LocalName, context.Namespace), sourceUri, lineNo, linePos), XmlSeverityType.Error);
2159 Debug.Assert(names.Count > 0);
2160 if (context.TooComplex) {
2161 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContentExpectingComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), PrintExpectedElements(names, getParticles), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2164 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContentExpecting, new string[] { BuildElementName(context.LocalName, context.Namespace), PrintExpectedElements(names, getParticles) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2169 internal static string PrintExpectedElements(ArrayList expected, bool getParticles) {
2171 string ContinuationString = Res.GetString(Res.Sch_ContinuationString, new string[] {" "});
2172 XmlSchemaParticle currentParticle = null;
2173 XmlSchemaParticle nextParticle = null;
2174 XmlQualifiedName currentQName;
2175 ArrayList expectedNames = new ArrayList();
2176 StringBuilder builder = new StringBuilder();
2178 if (expected.Count == 1) {
2179 nextParticle = expected[0] as XmlSchemaParticle;
2182 for (int i=1; i < expected.Count; i++) {
2183 currentParticle = expected[i-1] as XmlSchemaParticle;
2184 nextParticle = expected[i] as XmlSchemaParticle;
2185 currentQName = currentParticle.GetQualifiedName();
2186 if (currentQName.Namespace != nextParticle.GetQualifiedName().Namespace) {
2187 expectedNames.Add(currentQName);
2188 PrintNamesWithNS(expectedNames, builder);
2189 expectedNames.Clear();
2190 Debug.Assert(builder.Length != 0);
2191 builder.Append(ContinuationString);
2194 expectedNames.Add(currentQName);
2199 expectedNames.Add(nextParticle.GetQualifiedName());
2200 PrintNamesWithNS(expectedNames, builder);
2202 return builder.ToString();
2205 return PrintNames(expected);
2209 private static string PrintNames(ArrayList expected) {
2210 StringBuilder builder = new StringBuilder();
2211 builder.Append(Quote);
2212 builder.Append(expected[0].ToString());
2213 for (int i = 1; i < expected.Count; ++i) {
2214 builder.Append(" ");
2215 builder.Append(expected[i].ToString());
2217 builder.Append(Quote);
2218 return builder.ToString();
2221 private static void PrintNamesWithNS(ArrayList expected, StringBuilder builder) {
2222 XmlQualifiedName name = null;
2223 name = expected[0] as XmlQualifiedName;
2224 if (expected.Count == 1) { //In case of one element in a namespace or any
2225 if (name.Name == "*") { //Any
2226 EnumerateAny(builder, name.Namespace);
2229 if (name.Namespace.Length != 0) {
2230 builder.Append(Res.GetString(Res.Sch_ElementNameAndNamespace, name.Name, name.Namespace));
2233 builder.Append(Res.GetString(Res.Sch_ElementName, name.Name));
2238 bool foundAny = false;
2240 StringBuilder subBuilder = new StringBuilder();
2241 for (int i = 0; i < expected.Count; i++) {
2242 name = expected[i] as XmlQualifiedName;
2243 if (name.Name == "*") { //rare case where ns of element and that of Any match
2251 subBuilder.Append(", ");
2253 subBuilder.Append(name.Name);
2256 subBuilder.Append(", ");
2257 subBuilder.Append(Res.GetString(Res.Sch_AnyElement));
2260 if (name.Namespace.Length != 0) {
2261 builder.Append(Res.GetString(Res.Sch_ElementNameAndNamespace, subBuilder.ToString(), name.Namespace));
2264 builder.Append(Res.GetString(Res.Sch_ElementName, subBuilder.ToString()));
2270 private static void EnumerateAny(StringBuilder builder, string namespaces) {
2271 StringBuilder subBuilder = new StringBuilder();
2272 if (namespaces == "##any" || namespaces == "##other") {
2273 subBuilder.Append(namespaces);
2276 string[] nsList = XmlConvert.SplitString(namespaces);
2277 Debug.Assert(nsList.Length > 0);
2278 subBuilder.Append(nsList[0]);
2279 for (int i = 1; i < nsList.Length; i++) {
2280 subBuilder.Append(", ");
2281 subBuilder.Append(nsList[i]);
2284 builder.Append(Res.GetString(Res.Sch_AnyElementNS, subBuilder.ToString()));
2287 internal static string QNameString(string localName, string ns) {
2288 return (ns.Length != 0) ? string.Concat(ns, ":", localName) : localName;
2291 internal static string BuildElementName(XmlQualifiedName qname) {
2292 return BuildElementName(qname.Name, qname.Namespace);
2295 internal static string BuildElementName(string localName, string ns) {
2296 if (ns.Length != 0) {
2297 return Res.GetString(Res.Sch_ElementNameAndNamespace, localName, ns);
2300 return Res.GetString(Res.Sch_ElementName, localName);
2304 private void ProcessEntity(string name) {
2305 if (!this.checkEntity) {
2308 IDtdEntityInfo entityInfo = null;
2309 if (dtdSchemaInfo != null) {
2310 entityInfo = dtdSchemaInfo.LookupEntity(name);
2312 if (entityInfo == null) {
2313 // validation error, see xml spec [68]
2314 SendValidationEvent(Res.Sch_UndeclaredEntity, name);
2316 else if (entityInfo.IsUnparsedEntity) {
2317 // validation error, see xml spec [68]
2318 SendValidationEvent(Res.Sch_UnparsedEntityRef, name);
2322 private void SendValidationEvent(string code) {
2323 SendValidationEvent(code, string.Empty);
2326 private void SendValidationEvent(string code, string[] args) {
2327 SendValidationEvent(new XmlSchemaValidationException(code, args, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition));
2330 private void SendValidationEvent(string code, string arg) {
2331 SendValidationEvent(new XmlSchemaValidationException(code, arg, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition));
2334 private void SendValidationEvent(string code, string arg1, string arg2) {
2335 SendValidationEvent(new XmlSchemaValidationException(code, new string[] { arg1, arg2 }, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition));
2338 private void SendValidationEvent(string code, string[] args, Exception innerException, XmlSeverityType severity) {
2339 if (severity != XmlSeverityType.Warning || ReportValidationWarnings) {
2340 SendValidationEvent(new XmlSchemaValidationException(code, args, innerException, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition), severity);
2344 private void SendValidationEvent(string code, string[] args, Exception innerException) {
2345 SendValidationEvent(new XmlSchemaValidationException(code, args, innerException, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition), XmlSeverityType.Error);
2348 private void SendValidationEvent(XmlSchemaValidationException e) {
2349 SendValidationEvent(e, XmlSeverityType.Error);
2352 private void SendValidationEvent(XmlSchemaException e) {
2353 SendValidationEvent(new XmlSchemaValidationException(e.GetRes,e.Args,e.SourceUri,e.LineNumber,e.LinePosition), XmlSeverityType.Error);
2356 private void SendValidationEvent(string code, string msg, XmlSeverityType severity) {
2357 if (severity != XmlSeverityType.Warning || ReportValidationWarnings) {
2358 SendValidationEvent(new XmlSchemaValidationException(code, msg, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition), severity);
2362 private void SendValidationEvent(XmlSchemaValidationException e, XmlSeverityType severity) {
2363 bool errorSeverity = false;
2364 if (severity == XmlSeverityType.Error) {
2365 errorSeverity = true;
2366 context.Validity = XmlSchemaValidity.Invalid;
2368 if (errorSeverity) {
2369 if (eventHandler != null) {
2370 eventHandler(validationEventSender, new ValidationEventArgs(e, severity));
2376 else if (ReportValidationWarnings && eventHandler != null) {
2377 eventHandler(validationEventSender, new ValidationEventArgs(e, severity));
2381 internal static void SendValidationEvent(ValidationEventHandler eventHandler, object sender, XmlSchemaValidationException e, XmlSeverityType severity) {
2382 if (eventHandler != null) {
2383 eventHandler(sender, new ValidationEventArgs(e, severity));
2385 else if (severity == XmlSeverityType.Error) {
2391 } //End of namespace