The Labs \ Source Viewer \ SSCLI \ System.Xml.Schema \ XsdValidator

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XsdValidator.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">priyal</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Schema
  17. {
  18.    
  19.     using System.Collections;
  20.     using System.Collections.Specialized;
  21.     using System.Text;
  22.     using System.IO;
  23.     using System.Diagnostics;
  24.     using System.Xml.Schema;
  25.     using System.Xml.XPath;
  26.    
  27.     #pragma warning disable 618
  28.     internal sealed class XsdValidator : BaseValidator
  29.     {
  30.        
  31.         private int startIDConstraint = -1;
  32.         private const int STACK_INCREMENT = 10;
  33.         private HWStack validationStack;
  34.         // validaton contexts
  35.         private Hashtable attPresence;
  36.         private XmlNamespaceManager nsManager;
  37.         private bool bManageNamespaces = false;
  38.         private Hashtable IDs;
  39.         private IdRefNode idRefListHead;
  40.         private Parser inlineSchemaParser = null;
  41.         private XmlSchemaContentProcessing processContents;
  42.        
  43.         private static readonly XmlSchemaDatatype dtCDATA = XmlSchemaDatatype.FromXmlTokenizedType(XmlTokenizedType.CDATA);
  44.         private static readonly XmlSchemaDatatype dtQName = XmlSchemaDatatype.FromXmlTokenizedTypeXsd(XmlTokenizedType.QName);
  45.         private static readonly XmlSchemaDatatype dtStringArray = dtCDATA.DeriveByList(null);
  46.        
  47.         //To avoid SchemaNames creation
  48.         private string NsXmlNs;
  49.         private string NsXs;
  50.         private string NsXsi;
  51.         private string XsiType;
  52.         private string XsiNil;
  53.         private string XsiSchemaLocation;
  54.         private string XsiNoNamespaceSchemaLocation;
  55.         private string XsdSchema;
  56.        
  57.        
  58.         internal XsdValidator(BaseValidator validator) : base(validator)
  59.         {
  60.             Init();
  61.         }
  62.        
  63.         internal XsdValidator(XmlValidatingReaderImpl reader, XmlSchemaCollection schemaCollection, ValidationEventHandler eventHandler) : base(reader, schemaCollection, eventHandler)
  64.         {
  65.             Init();
  66.         }
  67.        
  68.         private void Init()
  69.         {
  70.             nsManager = reader.NamespaceManager;
  71.             if (nsManager == null) {
  72.                 nsManager = new XmlNamespaceManager(NameTable);
  73.                 bManageNamespaces = true;
  74.             }
  75.             validationStack = new HWStack(STACK_INCREMENT);
  76.             textValue = new StringBuilder();
  77.             attPresence = new Hashtable();
  78.             schemaInfo = new SchemaInfo();
  79.             checkDatatype = false;
  80.             processContents = XmlSchemaContentProcessing.Strict;
  81.             Push(XmlQualifiedName.Empty);
  82.            
  83.             //Add common strings to be compared to NameTable
  84.             NsXmlNs = NameTable.Add(XmlReservedNs.NsXmlNs);
  85.             NsXs = NameTable.Add(XmlReservedNs.NsXs);
  86.             NsXsi = NameTable.Add(XmlReservedNs.NsXsi);
  87.             XsiType = NameTable.Add("type");
  88.             XsiNil = NameTable.Add("nil");
  89.             XsiSchemaLocation = NameTable.Add("schemaLocation");
  90.             XsiNoNamespaceSchemaLocation = NameTable.Add("noNamespaceSchemaLocation");
  91.             XsdSchema = NameTable.Add("schema");
  92.         }
  93.        
  94.         public override void Validate()
  95.         {
  96.             if (IsInlineSchemaStarted) {
  97.                 ProcessInlineSchema();
  98.             }
  99.             else {
  100.                 switch (reader.NodeType) {
  101.                     case XmlNodeType.Element:
  102.                         ValidateElement();
  103.                         if (reader.IsEmptyElement) {
  104.                             goto case XmlNodeType.EndElement;
  105.                         }
  106.                         break;
  107.                     case XmlNodeType.Whitespace:
  108.                         ValidateWhitespace();
  109.                         break;
  110.                     case XmlNodeType.Text:
  111.                     case XmlNodeType.CDATA:
  112.                     case XmlNodeType.SignificantWhitespace:
  113.                         // text inside a node
  114.                         // <![CDATA[...]]>
  115.                         ValidateText();
  116.                         break;
  117.                     case XmlNodeType.EndElement:
  118.                         ValidateEndElement();
  119.                         break;
  120.                 }
  121.             }
  122.         }
  123.        
  124.        
  125.         public override void CompleteValidation()
  126.         {
  127.             CheckForwardRefs();
  128.         }
  129.        
  130.         //for frag validation
  131.         public ValidationState Context {
  132.             set { context = value; }
  133.         }
  134.        
  135.         //share for frag validation
  136.         public static XmlSchemaDatatype DtQName {
  137.             get { return dtQName; }
  138.         }
  139.        
  140.         private bool IsInlineSchemaStarted {
  141.             get { return inlineSchemaParser != null; }
  142.         }
  143.        
  144.         private void ProcessInlineSchema()
  145.         {
  146.             if (!inlineSchemaParser.ParseReaderNode()) {
  147.                 // Done
  148.                 inlineSchemaParser.FinishParsing();
  149.                 XmlSchema schema = inlineSchemaParser.XmlSchema;
  150.                 string inlineNS = null;
  151.                 if (schema != null && schema.ErrorCount == 0) {
  152.                     try {
  153.                         SchemaInfo inlineSchemaInfo = new SchemaInfo();
  154.                         inlineSchemaInfo.SchemaType = SchemaType.XSD;
  155.                         inlineNS = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
  156.                         if (!SchemaInfo.TargetNamespaces.Contains(inlineNS)) {
  157.                             if (SchemaCollection.Add(inlineNS, inlineSchemaInfo, schema, true) != null) {
  158.                                 //If no errors on compile
  159.                                 //Add to validator's SchemaInfo
  160.                                 SchemaInfo.Add(inlineSchemaInfo, EventHandler);
  161.                             }
  162.                         }
  163.                     }
  164.                     catch (XmlSchemaException e) {
  165.                         SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {BaseUri.AbsoluteUri, e.Message}, XmlSeverityType.Error);
  166.                     }
  167.                 }
  168.                 inlineSchemaParser = null;
  169.             }
  170.         }
  171.        
  172.         private void ValidateElement()
  173.         {
  174.             elementName.Init(reader.LocalName, reader.NamespaceURI);
  175.             object particle = ValidateChildElement();
  176.             if (IsXSDRoot(elementName.Name, elementName.Namespace) && reader.Depth > 0) {
  177.                 inlineSchemaParser = new Parser(SchemaType.XSD, NameTable, SchemaNames, EventHandler);
  178.                 inlineSchemaParser.StartParsing(reader, null);
  179.                 inlineSchemaParser.ParseReaderNode();
  180.             }
  181.             else {
  182.                 ProcessElement(particle);
  183.             }
  184.         }
  185.        
  186.         private object ValidateChildElement()
  187.         {
  188.             object particle = null;
  189.             int errorCode = 0;
  190.             if (context.NeedValidateChildren) {
  191.                 if (context.IsNill) {
  192.                     SendValidationEvent(Res.Sch_ContentInNill, elementName.ToString());
  193.                     return null;
  194.                 }
  195.                 particle = context.ElementDecl.ContentValidator.ValidateElement(elementName, context, out errorCode);
  196.                 if (particle == null) {
  197.                     processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
  198.                     if (errorCode == -2) {
  199.                         //ContentModel all group error
  200.                         SendValidationEvent(Res.Sch_AllElement, elementName.ToString());
  201.                     }
  202.                     XmlSchemaValidator.ElementValidationError(elementName, context, EventHandler, reader, reader.BaseURI, PositionInfo.LineNumber, PositionInfo.LinePosition, false);
  203.                 }
  204.             }
  205.             return particle;
  206.         }
  207.        
  208.         private void ProcessElement(object particle)
  209.         {
  210.             XmlQualifiedName xsiType;
  211.             string xsiNil;
  212.             SchemaElementDecl elementDecl = FastGetElementDecl(particle);
  213.             Push(elementName);
  214.             if (bManageNamespaces) {
  215.                 nsManager.PushScope();
  216.             }
  217.             ProcessXsiAttributes(out xsiType, out xsiNil);
  218.             if (processContents != XmlSchemaContentProcessing.Skip) {
  219.                 if (elementDecl == null || !xsiType.IsEmpty || xsiNil != null) {
  220.                     elementDecl = ThoroughGetElementDecl(elementDecl, xsiType, xsiNil);
  221.                 }
  222.                 if (elementDecl == null) {
  223.                     if (HasSchema && processContents == XmlSchemaContentProcessing.Strict) {
  224.                         SendValidationEvent(Res.Sch_UndeclaredElement, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace));
  225.                     }
  226.                     else {
  227.                         SendValidationEvent(Res.Sch_NoElementSchemaFound, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace), XmlSeverityType.Warning);
  228.                     }
  229.                 }
  230.             }
  231.            
  232.             context.ElementDecl = elementDecl;
  233.             ValidateStartElementIdentityConstraints();
  234.             ValidateStartElement();
  235.             if (context.ElementDecl != null) {
  236.                 ValidateEndStartElement();
  237.                 context.NeedValidateChildren = processContents != XmlSchemaContentProcessing.Skip;
  238.                 context.ElementDecl.ContentValidator.InitValidation(context);
  239.             }
  240.         }
  241.        
  242.         private void ProcessXsiAttributes(out XmlQualifiedName xsiType, out string xsiNil)
  243.         {
  244.             string[] xsiSchemaLocation = null;
  245.             string xsiNoNamespaceSchemaLocation = null;
  246.             xsiType = XmlQualifiedName.Empty;
  247.             xsiNil = null;
  248.            
  249.             if (reader.Depth == 0) {
  250.                 //Load schema for empty namespace
  251.                 LoadSchema(string.Empty, null);
  252.                
  253.                 //Should load schemas for namespaces already added to nsManager
  254.                 foreach (string ns in nsManager.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml).Values) {
  255.                     LoadSchema(ns, null);
  256.                 }
  257.             }
  258.            
  259.             if (reader.MoveToFirstAttribute()) {
  260.                 do {
  261.                     string objectNs = reader.NamespaceURI;
  262.                     string objectName = reader.LocalName;
  263.                     if (Ref.Equal(objectNs, NsXmlNs)) {
  264.                         LoadSchema(reader.Value, null);
  265.                         if (bManageNamespaces) {
  266.                             nsManager.AddNamespace(reader.Prefix.Length == 0 ? string.Empty : reader.LocalName, reader.Value);
  267.                         }
  268.                     }
  269.                     else if (Ref.Equal(objectNs, NsXsi)) {
  270.                         if (Ref.Equal(objectName, XsiSchemaLocation)) {
  271.                             xsiSchemaLocation = (string[])dtStringArray.ParseValue(reader.Value, NameTable, nsManager);
  272.                         }
  273.                         else if (Ref.Equal(objectName, XsiNoNamespaceSchemaLocation)) {
  274.                             xsiNoNamespaceSchemaLocation = reader.Value;
  275.                         }
  276.                         else if (Ref.Equal(objectName, XsiType)) {
  277.                             xsiType = (XmlQualifiedName)dtQName.ParseValue(reader.Value, NameTable, nsManager);
  278.                         }
  279.                         else if (Ref.Equal(objectName, XsiNil)) {
  280.                             xsiNil = reader.Value;
  281.                         }
  282.                     }
  283.                 }
  284.                 while (reader.MoveToNextAttribute());
  285.                 reader.MoveToElement();
  286.             }
  287.             if (xsiNoNamespaceSchemaLocation != null) {
  288.                 LoadSchema(string.Empty, xsiNoNamespaceSchemaLocation);
  289.             }
  290.             if (xsiSchemaLocation != null) {
  291.                 for (int i = 0; i < xsiSchemaLocation.Length - 1; i += 2) {
  292.                     LoadSchema((string)xsiSchemaLocation[i], (string)xsiSchemaLocation[i + 1]);
  293.                 }
  294.             }
  295.         }
  296.        
  297.         private void ValidateEndElement()
  298.         {
  299.             if (bManageNamespaces) {
  300.                 nsManager.PopScope();
  301.             }
  302.             if (context.ElementDecl != null) {
  303.                 if (!context.IsNill) {
  304.                     if (context.NeedValidateChildren) {
  305.                         if (!context.ElementDecl.ContentValidator.CompleteValidation(context)) {
  306.                             XmlSchemaValidator.CompleteValidationError(context, EventHandler, reader, reader.BaseURI, PositionInfo.LineNumber, PositionInfo.LinePosition, false);
  307.                         }
  308.                     }
  309.                    
  310.                     if (checkDatatype && !context.IsNill) {
  311.                         string stringValue = !hasSibling ? textString : textValue.ToString();
  312.                         // only for identity-constraint exception reporting
  313.                         if (!(stringValue.Length == 0 && context.ElementDecl.DefaultValueTyped != null)) {
  314.                             CheckValue(stringValue, null);
  315.                             checkDatatype = false;
  316.                         }
  317.                     }
  318.                 }
  319.                
  320.                 // for each level in the stack, endchildren and fill value from element
  321.                 if (HasIdentityConstraints) {
  322.                     EndElementIdentityConstraints();
  323.                 }
  324.             }
  325.             Pop();
  326.            
  327.         }
  328.        
  329.         private SchemaElementDecl FastGetElementDecl(object particle)
  330.         {
  331.             SchemaElementDecl elementDecl = null;
  332.             if (particle != null) {
  333.                 XmlSchemaElement element = particle as XmlSchemaElement;
  334.                 if (element != null) {
  335.                     elementDecl = element.ElementDecl;
  336.                 }
  337.                 else {
  338.                     XmlSchemaAny any = (XmlSchemaAny)particle;
  339.                     processContents = any.ProcessContentsCorrect;
  340.                 }
  341.             }
  342.             return elementDecl;
  343.         }
  344.        
  345.         private SchemaElementDecl ThoroughGetElementDecl(SchemaElementDecl elementDecl, XmlQualifiedName xsiType, string xsiNil)
  346.         {
  347.             if (elementDecl == null) {
  348.                 elementDecl = schemaInfo.GetElementDecl(elementName);
  349.             }
  350.             if (elementDecl != null) {
  351.                 if (xsiType.IsEmpty) {
  352.                     if (elementDecl.IsAbstract) {
  353.                         SendValidationEvent(Res.Sch_AbstractElement, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace));
  354.                         elementDecl = null;
  355.                     }
  356.                 }
  357.                 else if (xsiNil != null && xsiNil.Equals("true")) {
  358.                     SendValidationEvent(Res.Sch_XsiNilAndType);
  359.                 }
  360.                 else {
  361.                     SchemaElementDecl elementDeclXsi = (SchemaElementDecl)schemaInfo.ElementDeclsByType[xsiType];
  362.                     if (elementDeclXsi == null && xsiType.Namespace == NsXs) {
  363.                         XmlSchemaSimpleType simpleType = DatatypeImplementation.GetSimpleTypeFromXsdType(new XmlQualifiedName(xsiType.Name, NsXs));
  364.                         if (simpleType != null) {
  365.                             elementDeclXsi = simpleType.ElementDecl;
  366.                         }
  367.                     }
  368.                     if (elementDeclXsi == null) {
  369.                         SendValidationEvent(Res.Sch_XsiTypeNotFound, xsiType.ToString());
  370.                         elementDecl = null;
  371.                     }
  372.                     else if (!XmlSchemaType.IsDerivedFrom(elementDeclXsi.SchemaType, elementDecl.SchemaType, elementDecl.Block)) {
  373.                         SendValidationEvent(Res.Sch_XsiTypeBlockedEx, new string[] {xsiType.ToString(), XmlSchemaValidator.QNameString(context.LocalName, context.Namespace)});
  374.                         elementDecl = null;
  375.                     }
  376.                     else {
  377.                         elementDecl = elementDeclXsi;
  378.                     }
  379.                 }
  380.                 if (elementDecl != null && elementDecl.IsNillable) {
  381.                     if (xsiNil != null) {
  382.                         context.IsNill = XmlConvert.ToBoolean(xsiNil);
  383.                         if (context.IsNill && elementDecl.DefaultValueTyped != null) {
  384.                             SendValidationEvent(Res.Sch_XsiNilAndFixed);
  385.                         }
  386.                     }
  387.                 }
  388.                 else if (xsiNil != null) {
  389.                     SendValidationEvent(Res.Sch_InvalidXsiNill);
  390.                 }
  391.             }
  392.             return elementDecl;
  393.         }
  394.        
  395.         private void ValidateStartElement()
  396.         {
  397.             if (context.ElementDecl != null) {
  398.                 if (context.ElementDecl.IsAbstract) {
  399.                     SendValidationEvent(Res.Sch_AbstractElement, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace));
  400.                 }
  401.                
  402.                 reader.SchemaTypeObject = context.ElementDecl.SchemaType;
  403.                
  404.                 if (reader.IsEmptyElement && !context.IsNill && context.ElementDecl.DefaultValueTyped != null) {
  405.                     reader.TypedValueObject = UnWrapUnion(context.ElementDecl.DefaultValueTyped);
  406.                     context.IsNill = true;
  407.                     // reusing IsNill
  408.                 }
  409.                 else {
  410.                     reader.TypedValueObject = null;
  411.                     //Typed value cleanup
  412.                 }
  413.                 if (this.context.ElementDecl.HasRequiredAttribute || HasIdentityConstraints) {
  414.                     attPresence.Clear();
  415.                 }
  416.             }
  417.            
  418.             if (reader.MoveToFirstAttribute()) {
  419.                 do {
  420.                     if ((object)reader.NamespaceURI == (object)NsXmlNs) {
  421.                         continue;
  422.                     }
  423.                     if ((object)reader.NamespaceURI == (object)NsXsi) {
  424.                         continue;
  425.                     }
  426.                    
  427.                     try {
  428.                         reader.SchemaTypeObject = null;
  429.                         XmlQualifiedName attQName = new XmlQualifiedName(reader.LocalName, reader.NamespaceURI);
  430.                         bool skipContents = (processContents == XmlSchemaContentProcessing.Skip);
  431.                         SchemaAttDef attnDef = schemaInfo.GetAttributeXsd(context.ElementDecl, attQName, ref skipContents);
  432.                        
  433.                         if (attnDef != null) {
  434.                             if (context.ElementDecl != null && (context.ElementDecl.HasRequiredAttribute || this.startIDConstraint != -1)) {
  435.                                 attPresence.Add(attnDef.Name, attnDef);
  436.                             }
  437.                             Debug.Assert(attnDef.SchemaType != null);
  438.                             reader.SchemaTypeObject = attnDef.SchemaType;
  439.                             if (attnDef.Datatype != null) {
  440.                                
  441.                                 // need to check the contents of this attribute to make sure
  442.                                 // it is valid according to the specified attribute type.
  443.                                 CheckValue(reader.Value, attnDef);
  444.                             }
  445.                             if (HasIdentityConstraints) {
  446.                                 AttributeIdentityConstraints(reader.LocalName, reader.NamespaceURI, reader.TypedValueObject, reader.Value, attnDef);
  447.                             }
  448.                         }
  449.                         else if (!skipContents) {
  450.                             if (context.ElementDecl == null && processContents == XmlSchemaContentProcessing.Strict && attQName.Namespace.Length != 0 && schemaInfo.Contains(attQName.Namespace)) {
  451.                                 SendValidationEvent(Res.Sch_UndeclaredAttribute, attQName.ToString());
  452.                             }
  453.                             else {
  454.                                 SendValidationEvent(Res.Sch_NoAttributeSchemaFound, attQName.ToString(), XmlSeverityType.Warning);
  455.                             }
  456.                         }
  457.                     }
  458.                     catch (XmlSchemaException e) {
  459.                         e.SetSource(reader.BaseURI, PositionInfo.LineNumber, PositionInfo.LinePosition);
  460.                         SendValidationEvent(e);
  461.                     }
  462.                 }
  463.                 while (reader.MoveToNextAttribute());
  464.                 reader.MoveToElement();
  465.             }
  466.         }
  467.        
  468.         private void ValidateEndStartElement()
  469.         {
  470.             if (context.ElementDecl.HasDefaultAttribute) {
  471.                 foreach (SchemaAttDef attdef in context.ElementDecl.DefaultAttDefs) {
  472.                     reader.AddDefaultAttribute(attdef);
  473.                     // even default attribute i have to move to... but can't exist
  474.                     if (HasIdentityConstraints && !attPresence.Contains(attdef.Name)) {
  475.                         AttributeIdentityConstraints(attdef.Name.Name, attdef.Name.Namespace, UnWrapUnion(attdef.DefaultValueTyped), attdef.DefaultValueRaw, attdef);
  476.                     }
  477.                 }
  478.             }
  479.            
  480.             if (context.ElementDecl.HasRequiredAttribute) {
  481.                 try {
  482.                     context.ElementDecl.CheckAttributes(attPresence, reader.StandAlone);
  483.                 }
  484.                 catch (XmlSchemaException e) {
  485.                     e.SetSource(reader.BaseURI, PositionInfo.LineNumber, PositionInfo.LinePosition);
  486.                     SendValidationEvent(e);
  487.                 }
  488.                
  489.             }
  490.             if (context.ElementDecl.Datatype != null) {
  491.                 checkDatatype = true;
  492.                 hasSibling = false;
  493.                 textString = string.Empty;
  494.                 textValue.Length = 0;
  495.             }
  496.         }
  497.        
  498.        
  499.        
  500.         private void LoadSchemaFromLocation(string uri, string url)
  501.         {
  502.            
  503.             XmlReader reader = null;
  504.             SchemaInfo schemaInfo = null;
  505.            
  506.             try {
  507.                 Uri ruri = this.XmlResolver.ResolveUri(BaseUri, url);
  508.                 Stream stm = (Stream)this.XmlResolver.GetEntity(ruri, null, null);
  509.                 reader = new XmlTextReader(ruri.ToString(), stm, NameTable);
  510.                 //XmlSchema schema = SchemaCollection.Add(uri, reader, this.XmlResolver);
  511.                
  512.                 Parser parser = new Parser(SchemaType.XSD, NameTable, SchemaNames, EventHandler);
  513.                 parser.XmlResolver = this.XmlResolver;
  514.                 SchemaType schemaType = parser.Parse(reader, uri);
  515.                
  516.                 schemaInfo = new SchemaInfo();
  517.                 schemaInfo.SchemaType = schemaType;
  518.                 if (schemaType == SchemaType.XSD) {
  519.                     if (SchemaCollection.EventHandler == null) {
  520.                         SchemaCollection.EventHandler = this.EventHandler;
  521.                     }
  522.                     SchemaCollection.Add(uri, schemaInfo, parser.XmlSchema, true);
  523.                 }
  524.                 //Add to validator's SchemaInfo
  525.                 SchemaInfo.Add(schemaInfo, EventHandler);
  526.                
  527.                 while (reader.Read())
  528.                     ;
  529.                 // wellformness check
  530.             }
  531.             catch (XmlSchemaException e) {
  532.                 schemaInfo = null;
  533.                 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, XmlSeverityType.Error);
  534.             }
  535.             catch (Exception e) {
  536.                 schemaInfo = null;
  537.                 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, XmlSeverityType.Warning);
  538.             }
  539.             finally {
  540.                 if (reader != null) {
  541.                     reader.Close();
  542.                 }
  543.             }
  544.         }
  545.        
  546.         private void LoadSchema(string uri, string url)
  547.         {
  548.             if (this.XmlResolver == null) {
  549.                 return;
  550.             }
  551.             if (SchemaInfo.TargetNamespaces.Contains(uri) && nsManager.LookupPrefix(uri) != null) {
  552.                 return;
  553.             }
  554.            
  555.             SchemaInfo schemaInfo = null;
  556.             if (SchemaCollection != null)
  557.                 schemaInfo = SchemaCollection.GetSchemaInfo(uri);
  558.             if (schemaInfo != null) {
  559.                 if (schemaInfo.SchemaType != SchemaType.XSD) {
  560.                     throw new XmlException(Res.Xml_MultipleValidaitonTypes, string.Empty, this.PositionInfo.LineNumber, this.PositionInfo.LinePosition);
  561.                 }
  562.                 SchemaInfo.Add(schemaInfo, EventHandler);
  563.                 return;
  564.             }
  565.             if (url != null) {
  566.                 LoadSchemaFromLocation(uri, url);
  567.             }
  568.         }
  569.        
  570.         private bool HasSchema {
  571.             get { return schemaInfo.SchemaType != SchemaType.None; }
  572.         }
  573.        
  574.         public override bool PreserveWhitespace {
  575.             get { return context.ElementDecl != null ? context.ElementDecl.ContentValidator.PreserveWhitespace : false; }
  576.         }
  577.        
  578.        
  579.         void ProcessTokenizedType(XmlTokenizedType ttype, string name)
  580.         {
  581.             switch (ttype) {
  582.                 case XmlTokenizedType.ID:
  583.                     if (FindId(name) != null) {
  584.                         SendValidationEvent(Res.Sch_DupId, name);
  585.                     }
  586.                     else {
  587.                         AddID(name, context.LocalName);
  588.                     }
  589.                     break;
  590.                 case XmlTokenizedType.IDREF:
  591.                     object p = FindId(name);
  592.                     if (p == null) {
  593.                         // add it to linked list to check it later
  594.                         idRefListHead = new IdRefNode(idRefListHead, name, this.PositionInfo.LineNumber, this.PositionInfo.LinePosition);
  595.                     }
  596.                     break;
  597.                 case XmlTokenizedType.ENTITY:
  598.                     ProcessEntity(schemaInfo, name, this, EventHandler, reader.BaseURI, PositionInfo.LineNumber, PositionInfo.LinePosition);
  599.                     break;
  600.                 default:
  601.                     break;
  602.             }
  603.         }
  604.        
  605.         private void CheckValue(string value, SchemaAttDef attdef)
  606.         {
  607.             try {
  608.                 reader.TypedValueObject = null;
  609.                 bool isAttn = attdef != null;
  610.                 XmlSchemaDatatype dtype = isAttn ? attdef.Datatype : context.ElementDecl.Datatype;
  611.                 if (dtype == null) {
  612.                     return;
  613.                     // no reason to check
  614.                 }
  615.                
  616.                 object typedValue = dtype.ParseValue(value, NameTable, nsManager, true);
  617.                
  618.                 // Check special types
  619.                 XmlTokenizedType ttype = dtype.TokenizedType;
  620.                 if (ttype == XmlTokenizedType.ENTITY || ttype == XmlTokenizedType.ID || ttype == XmlTokenizedType.IDREF) {
  621.                     if (dtype.Variety == XmlSchemaDatatypeVariety.List) {
  622.                         string[] ss = (string[])typedValue;
  623.                         foreach (string s in ss) {
  624.                             ProcessTokenizedType(dtype.TokenizedType, s);
  625.                         }
  626.                     }
  627.                     else {
  628.                         ProcessTokenizedType(dtype.TokenizedType, (string)typedValue);
  629.                     }
  630.                 }
  631.                
  632.                 SchemaDeclBase decl = isAttn ? (SchemaDeclBase)attdef : (SchemaDeclBase)context.ElementDecl;
  633.                 if (!decl.CheckValue(typedValue)) {
  634.                     if (isAttn) {
  635.                         SendValidationEvent(Res.Sch_FixedAttributeValue, attdef.Name.ToString());
  636.                     }
  637.                     else {
  638.                         SendValidationEvent(Res.Sch_FixedElementValue, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace));
  639.                     }
  640.                 }
  641.                 if (dtype.Variety == XmlSchemaDatatypeVariety.Union) {
  642.                     typedValue = UnWrapUnion(typedValue);
  643.                 }
  644.                 reader.TypedValueObject = typedValue;
  645.             }
  646.             catch (XmlSchemaException) {
  647.                 if (attdef != null) {
  648.                     SendValidationEvent(Res.Sch_AttributeValueDataType, attdef.Name.ToString());
  649.                 }
  650.                 else {
  651.                     SendValidationEvent(Res.Sch_ElementValueDataType, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace));
  652.                 }
  653.             }
  654.         }
  655.        
  656.        
  657.        
  658.         internal void AddID(string name, object node)
  659.         {
  660.             // Note: It used to be true that we only called this if _fValidate was true,
  661.             // but due to the fact that you can now dynamically type somethign as an ID
  662.             // that is no longer true.
  663.             if (IDs == null) {
  664.                 IDs = new Hashtable();
  665.             }
  666.            
  667.             IDs.Add(name, node);
  668.         }
  669.        
  670.         public override object FindId(string name)
  671.         {
  672.             return IDs == null ? null : IDs[name];
  673.         }
  674.        
  675.         public bool IsXSDRoot(string localName, string ns)
  676.         {
  677.             return Ref.Equal(ns, NsXs) && Ref.Equal(localName, XsdSchema);
  678.         }
  679.        
  680.         private void Push(XmlQualifiedName elementName)
  681.         {
  682.             context = (ValidationState)validationStack.Push();
  683.             if (context == null) {
  684.                 context = new ValidationState();
  685.                 validationStack.AddToTop(context);
  686.             }
  687.             context.LocalName = elementName.Name;
  688.             context.Namespace = elementName.Namespace;
  689.             context.HasMatched = false;
  690.             context.IsNill = false;
  691.             context.ProcessContents = processContents;
  692.             context.NeedValidateChildren = false;
  693.             context.Constr = null;
  694.             //resetting the constraints to be null incase context != null
  695.             // when pushing onto stack;
  696.         }
  697.        
  698.        
  699.         private void Pop()
  700.         {
  701.             if (validationStack.Length > 1) {
  702.                 validationStack.Pop();
  703.                 if (startIDConstraint == validationStack.Length) {
  704.                     startIDConstraint = -1;
  705.                 }
  706.                 context = (ValidationState)validationStack.Peek();
  707.                 processContents = context.ProcessContents;
  708.             }
  709.         }
  710.        
  711.         private void CheckForwardRefs()
  712.         {
  713.             IdRefNode next = idRefListHead;
  714.             while (next != null) {
  715.                 if (FindId(next.Id) == null) {
  716.                     SendValidationEvent(new XmlSchemaException(Res.Sch_UndeclaredId, next.Id, reader.BaseURI, next.LineNo, next.LinePos));
  717.                 }
  718.                 IdRefNode ptr = next.Next;
  719.                 next.Next = null;
  720.                 // unhook each object so it is cleaned up by Garbage Collector
  721.                 next = ptr;
  722.             }
  723.             // not needed any more.
  724.             idRefListHead = null;
  725.         }
  726.        
  727.        
  728.         private void ValidateStartElementIdentityConstraints()
  729.         {
  730.             // added on June 15, set the context here, so the stack can have them
  731.             if (context.ElementDecl != null) {
  732.                 if (context.ElementDecl.Constraints != null) {
  733.                     AddIdentityConstraints();
  734.                 }
  735.                 //foreach constraint in stack (including the current one)
  736.                 if (HasIdentityConstraints) {
  737.                     ElementIdentityConstraints();
  738.                 }
  739.             }
  740.         }
  741.        
  742.         private bool HasIdentityConstraints {
  743.             get { return startIDConstraint != -1; }
  744.         }
  745.        
  746.         private void AddIdentityConstraints()
  747.         {
  748.             context.Constr = new ConstraintStruct[context.ElementDecl.Constraints.Length];
  749.             int id = 0;
  750.             foreach (CompiledIdentityConstraint constraint in context.ElementDecl.Constraints) {
  751.                 context.Constr[id++] = new ConstraintStruct(constraint);
  752.             }
  753.             // foreach constraint /constraintstruct
  754.             // added on June 19, make connections between new keyref tables with key/unique tables in stack
  755.             // i can't put it in the above loop, coz there will be key on the same level
  756.             foreach (ConstraintStruct keyrefconstr in context.Constr) {
  757.                 if (keyrefconstr.constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref) {
  758.                     bool find = false;
  759.                     // go upwards checking or only in this level
  760.                     for (int level = this.validationStack.Length - 1; level >= ((this.startIDConstraint >= 0) ? this.startIDConstraint : this.validationStack.Length - 1); level--) {
  761.                         // no constraint for this level
  762.                         if (((ValidationState)(this.validationStack[level])).Constr == null) {
  763.                             continue;
  764.                         }
  765.                         // else
  766.                         foreach (ConstraintStruct constr in ((ValidationState)(this.validationStack[level])).Constr) {
  767.                             if (constr.constraint.name == keyrefconstr.constraint.refer) {
  768.                                 find = true;
  769.                                 if (constr.keyrefTable == null) {
  770.                                     constr.keyrefTable = new Hashtable();
  771.                                 }
  772.                                 keyrefconstr.qualifiedTable = constr.keyrefTable;
  773.                                 break;
  774.                             }
  775.                         }
  776.                        
  777.                         if (find) {
  778.                             break;
  779.                         }
  780.                     }
  781.                     if (!find) {
  782.                         // didn't find connections, throw exceptions
  783.                         SendValidationEvent(Res.Sch_RefNotInScope, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace));
  784.                     }
  785.                 }
  786.                 // finished dealing with keyref
  787.             }
  788.             // end foreach
  789.             // initial set
  790.             if (this.startIDConstraint == -1) {
  791.                 this.startIDConstraint = this.validationStack.Length - 1;
  792.             }
  793.         }
  794.        
  795.         private void ElementIdentityConstraints()
  796.         {
  797.             for (int i = this.startIDConstraint; i < this.validationStack.Length; i++) {
  798.                 // no constraint for this level
  799.                 if (((ValidationState)(this.validationStack[i])).Constr == null) {
  800.                     continue;
  801.                 }
  802.                
  803.                 // else
  804.                 foreach (ConstraintStruct conuct in ((ValidationState)(this.validationStack[i])).Constr) {
  805.                     // check selector from here
  806.                     if (conuct.axisSelector.MoveToStartElement(reader.LocalName, reader.NamespaceURI)) {
  807.                         // selector selects new node, activate a new set of fields
  808.                         Debug.WriteLine("Selector Match!");
  809.                         Debug.WriteLine("Name: " + reader.LocalName + "\t|\tURI: " + reader.NamespaceURI + "\n");
  810.                         // in which axisFields got updated
  811.                         conuct.axisSelector.PushKS(PositionInfo.LineNumber, PositionInfo.LinePosition);
  812.                     }
  813.                    
  814.                     // axisFields is not null, but may be empty
  815.                     foreach (LocatedActiveAxis laxis in conuct.axisFields) {
  816.                         // check field from here
  817.                         if (laxis.MoveToStartElement(reader.LocalName, reader.NamespaceURI)) {
  818.                             Debug.WriteLine("Element Field Match!");
  819.                             // checking simpleType / simpleContent
  820.                             if (context.ElementDecl != null) {
  821.                                 // nextElement can be null when xml/xsd are not valid
  822.                                 if (context.ElementDecl.Datatype == null) {
  823.                                     SendValidationEvent(Res.Sch_FieldSimpleTypeExpected, reader.LocalName);
  824.                                 }
  825.                                 else {
  826.                                     // can't fill value here, wait till later....
  827.                                     // fill type : xsdType
  828.                                     laxis.isMatched = true;
  829.                                     // since it's simpletyped element, the endchildren will come consequently... don't worry
  830.                                 }
  831.                             }
  832.                         }
  833.                     }
  834.                    
  835.                 }
  836.             }
  837.         }
  838.        
  839.         // facilitate modifying
  840.         private void AttributeIdentityConstraints(string name, string ns, object obj, string sobj, SchemaAttDef attdef)
  841.         {
  842.             for (int ci = this.startIDConstraint; ci < this.validationStack.Length; ci++) {
  843.                 // no constraint for this level
  844.                 if (((ValidationState)(this.validationStack[ci])).Constr == null) {
  845.                     continue;
  846.                 }
  847.                
  848.                 // else
  849.                 foreach (ConstraintStruct conuct in ((ValidationState)(this.validationStack[ci])).Constr) {
  850.                     // axisFields is not null, but may be empty
  851.                     foreach (LocatedActiveAxis laxis in conuct.axisFields) {
  852.                         // check field from here
  853.                         if (laxis.MoveToAttribute(name, ns)) {
  854.                             Debug.WriteLine("Attribute Field Match!");
  855.                             //attribute is only simpletype, so needn't checking...
  856.                             // can fill value here, yeah!!
  857.                             Debug.WriteLine("Attribute Field Filling Value!");
  858.                             Debug.WriteLine("Name: " + name + "\t|\tURI: " + ns + "\t|\tValue: " + obj + "\n");
  859.                             if (laxis.Ks[laxis.Column] != null) {
  860.                                 // should be evaluated to either an empty node-set or a node-set with exactly one member
  861.                                 // two matches...
  862.                                 SendValidationEvent(Res.Sch_FieldSingleValueExpected, name);
  863.                             }
  864.                             else if ((attdef != null) && (attdef.Datatype != null)) {
  865.                                 laxis.Ks[laxis.Column] = new TypedObject(obj, sobj, attdef.Datatype);
  866.                             }
  867.                         }
  868.                     }
  869.                 }
  870.             }
  871.         }
  872.        
  873.         private object UnWrapUnion(object typedValue)
  874.         {
  875.             XsdSimpleValue simpleValue = typedValue as XsdSimpleValue;
  876.             if (simpleValue != null) {
  877.                 typedValue = simpleValue.TypedValue;
  878.             }
  879.             return typedValue;
  880.         }
  881.        
  882.         private void EndElementIdentityConstraints()
  883.         {
  884.             for (int ci = this.validationStack.Length - 1; ci >= this.startIDConstraint; ci--) {
  885.                 // no constraint for this level
  886.                 if (((ValidationState)(this.validationStack[ci])).Constr == null) {
  887.                     continue;
  888.                 }
  889.                
  890.                 // else
  891.                 foreach (ConstraintStruct conuct in ((ValidationState)(this.validationStack[ci])).Constr) {
  892.                     // EndChildren
  893.                     // axisFields is not null, but may be empty
  894.                     foreach (LocatedActiveAxis laxis in conuct.axisFields) {
  895.                         // check field from here
  896.                         // isMatched is false when nextElement is null. so needn't change this part.
  897.                         if (laxis.isMatched) {
  898.                             Debug.WriteLine("Element Field Filling Value!");
  899.                             Debug.WriteLine("Name: " + reader.LocalName + "\t|\tURI: " + reader.NamespaceURI + "\t|\tValue: " + reader.TypedValueObject + "\n");
  900.                             // fill value
  901.                             laxis.isMatched = false;
  902.                             if (laxis.Ks[laxis.Column] != null) {
  903.                                 // [field...] should be evaluated to either an empty node-set or a node-set with exactly one member
  904.                                 // two matches... already existing field value in the table.
  905.                                 SendValidationEvent(Res.Sch_FieldSingleValueExpected, reader.LocalName);
  906.                             }
  907.                             else {
  908.                                 // for element, reader.Value = "";
  909.                                 string stringValue = !hasSibling ? textString : textValue.ToString();
  910.                                 // only for identity-constraint exception reporting
  911.                                 if (reader.TypedValueObject != null && stringValue.Length != 0) {
  912.                                     laxis.Ks[laxis.Column] = new TypedObject(reader.TypedValueObject, stringValue, context.ElementDecl.Datatype);
  913.                                 }
  914.                             }
  915.                         }
  916.                         // EndChildren
  917.                         laxis.EndElement(reader.LocalName, reader.NamespaceURI);
  918.                     }
  919.                    
  920.                     if (conuct.axisSelector.EndElement(reader.LocalName, reader.NamespaceURI)) {
  921.                         // insert key sequence into hash (+ located active axis tuple leave for later)
  922.                         KeySequence ks = conuct.axisSelector.PopKS();
  923.                         // unqualified keysequence are not allowed
  924.                         switch (conuct.constraint.Role) {
  925.                             case CompiledIdentityConstraint.ConstraintRole.Key:
  926.                                 if (!ks.IsQualified()) {
  927.                                     //Key's fields can't be null... if we can return context node's line info maybe it will be better
  928.                                     //only keymissing & keyduplicate reporting cases are necessary to be dealt with... 3 places...
  929.                                     SendValidationEvent(new XmlSchemaException(Res.Sch_MissingKey, conuct.constraint.name.ToString(), reader.BaseURI, ks.PosLine, ks.PosCol));
  930.                                 }
  931.                                 else if (conuct.qualifiedTable.Contains(ks)) {
  932.                                     SendValidationEvent(new XmlSchemaException(Res.Sch_DuplicateKey, new string[2] {ks.ToString(), conuct.constraint.name.ToString()}, reader.BaseURI, ks.PosLine, ks.PosCol));
  933.                                 }
  934.                                 else {
  935.                                     conuct.qualifiedTable.Add(ks, ks);
  936.                                 }
  937.                                 break;
  938.                             case CompiledIdentityConstraint.ConstraintRole.Unique:
  939.                                 if (!ks.IsQualified()) {
  940.                                     continue;
  941.                                 }
  942.                                 if (conuct.qualifiedTable.Contains(ks)) {
  943.                                     // unique or key checking confliction
  944.                                     SendValidationEvent(new XmlSchemaException(Res.Sch_DuplicateKey, new string[2] {ks.ToString(), conuct.constraint.name.ToString()}, reader.BaseURI, ks.PosLine, ks.PosCol));
  945.                                 }
  946.                                 else {
  947.                                     conuct.qualifiedTable.Add(ks, ks);
  948.                                 }
  949.                                 break;
  950.                             case CompiledIdentityConstraint.ConstraintRole.Keyref:
  951.                                 // is there any possibility:
  952.                                 // 2 keyrefs: value is equal, type is not
  953.                                 // both put in the hashtable, 1 reference, 1 not
  954.                                 if (conuct.qualifiedTable != null) {
  955.                                     //Will be null in cases when the keyref is outside the scope of the key, that is not allowed by our impl
  956.                                     if (!ks.IsQualified() || conuct.qualifiedTable.Contains(ks)) {
  957.                                         continue;
  958.                                     }
  959.                                     conuct.qualifiedTable.Add(ks, ks);
  960.                                 }
  961.                                 break;
  962.                         }
  963.                        
  964.                     }
  965.                 }
  966.             }
  967.            
  968.             // current level's constraint struct
  969.             ConstraintStruct[] vcs = ((ValidationState)(this.validationStack[this.validationStack.Length - 1])).Constr;
  970.             if (vcs != null) {
  971.                 // validating all referencing tables...
  972.                 foreach (ConstraintStruct conuct in vcs) {
  973.                     if ((conuct.constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref) || (conuct.keyrefTable == null)) {
  974.                         continue;
  975.                     }
  976.                     foreach (KeySequence ks in conuct.keyrefTable.Keys) {
  977.                         if (!conuct.qualifiedTable.Contains(ks)) {
  978.                             SendValidationEvent(new XmlSchemaException(Res.Sch_UnresolvedKeyref, ks.ToString(), reader.BaseURI, ks.PosLine, ks.PosCol));
  979.                         }
  980.                     }
  981.                 }
  982.             }
  983.         }
  984.        
  985.     }
  986.     #pragma warning restore 618
  987. }

Developer Fusion