2006-02-20 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaUtil.cs
1
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
10 // 
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 // 
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 using System;\r
23 using System.Xml;\r
24 using System.Collections;\r
25 using System.Text;\r
26 using Mono.Xml;\r
27 using Mono.Xml.Schema;\r
28 using System.Xml.Serialization;\r
29 \r
30 namespace System.Xml.Schema\r
31 {\r
32         /// <summary>\r
33         ///  All Methods in this class should use XmlConvert. Some Methods are not present in the\r
34         ///  MS Implementation. We should provide them.\r
35         /// </summary>\r
36         internal class XmlSchemaUtil\r
37         {\r
38                 static XmlSchemaUtil ()\r
39                 {\r
40                         FinalAllowed = XmlSchemaDerivationMethod.Restriction | \r
41                                 XmlSchemaDerivationMethod.Extension;\r
42                         ComplexTypeBlockAllowed = FinalAllowed;\r
43                         ElementBlockAllowed = XmlSchemaDerivationMethod.Substitution | \r
44                                 FinalAllowed;\r
45                 }\r
46 \r
47                 internal static XmlSchemaDerivationMethod FinalAllowed;\r
48                 internal static XmlSchemaDerivationMethod ElementBlockAllowed;\r
49                 internal static XmlSchemaDerivationMethod ComplexTypeBlockAllowed;\r
50 \r
51 \r
52                 public static void AddToTable (XmlSchemaObjectTable table, XmlSchemaObject obj,\r
53                         XmlQualifiedName qname, ValidationEventHandler h)\r
54                 {\r
55                         if (table.Contains (qname)) {\r
56                                 // FIXME: This logic unexpectedly allows \r
57                                 // one redefining item and two or more redefining items.\r
58                                 // FIXME: redefining item is not simple replacement,\r
59                                 // but much more complex stuff.\r
60                                 if (obj.isRedefineChild) {      // take precedence.\r
61                                         if (obj.redefinedObject != null)\r
62                                                 obj.error (h, String.Format ("Named item {0} was already contained in the schema object table.", qname));\r
63                                         else\r
64                                                 obj.redefinedObject = table [qname];\r
65                                         table.Set (qname, obj);\r
66                                 }\r
67                                 else if (table [qname].isRedefineChild) {\r
68                                         if (table [qname].redefinedObject != null)\r
69                                                 obj.error (h, String.Format ("Named item {0} was already contained in the schema object table.", qname));\r
70                                         else\r
71                                                 table [qname].redefinedObject = obj;\r
72                                         return; // never add to the table.\r
73                                 }\r
74                                 else\r
75                                         obj.error (h, String.Format ("Named item {0} was already contained in the schema object table.", qname));\r
76                         }\r
77                         else\r
78                                 table.Set (qname, obj);\r
79                 }\r
80 \r
81                 public static void CompileID (string id,  XmlSchemaObject xso, Hashtable idCollection, ValidationEventHandler h)\r
82                 {\r
83                         //check if the string conforms to http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/datatypes.html#ID\r
84                         // 1. ID must be a NCName\r
85                         // 2. ID must be unique in the schema\r
86                         if(id == null)\r
87                                 return;\r
88                         if(!CheckNCName(id)) \r
89                                 xso.error(h,id+" is not a valid id attribute");\r
90                         else if(idCollection.ContainsKey(id))\r
91                                 xso.error(h,"Duplicate id attribute "+id);\r
92                         else\r
93                                 idCollection.Add(id,xso);\r
94                 }\r
95 \r
96                 public static bool CheckAnyUri (string uri)\r
97                 {\r
98                         if (uri.StartsWith ("##"))\r
99                                 return false;\r
100                         return true;\r
101                 }\r
102 \r
103                 public static bool CheckNormalizedString (string token)\r
104                 {\r
105                         return true;\r
106                 }\r
107 \r
108                 public static bool CheckNCName (string name)\r
109                 {\r
110                         //check if the string conforms to http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/datatypes.html#NCName\r
111                         return XmlChar.IsNCName (name);\r
112                 }\r
113 \r
114                 public static bool CheckQName (XmlQualifiedName qname)\r
115                 {\r
116                         // What is this doing?\r
117                         return true;\r
118                 }\r
119 \r
120                 public static XmlParserContext GetParserContext (XmlReader reader)\r
121                 {\r
122                         IHasXmlParserContext xctx = reader as IHasXmlParserContext;\r
123                         if (xctx != null)\r
124                                 return xctx.ParserContext;\r
125 \r
126                         return null;\r
127                 }\r
128 \r
129                 public static bool IsBuiltInDatatypeName (XmlQualifiedName qname)\r
130                 {\r
131                         if (qname.Namespace == XmlSchema.XdtNamespace) {\r
132                                 switch (qname.Name) {\r
133                                 case "anyAtomicType":\r
134                                 case "untypedAtomic":\r
135                                 case "dayTimeDuration":\r
136                                 case "yearMonthDuration":\r
137                                         return true;\r
138                                 default:\r
139                                         return false;\r
140                                 }\r
141                         }\r
142                         if (qname.Namespace != XmlSchema.Namespace)\r
143                                 return false;\r
144                         switch (qname.Name) {\r
145                         case "anySimpleType":\r
146                         case "duration": case "dateTime": case "time":\r
147                         case "date": case "gYearMonth": case "gYear":\r
148                         case "gMonthDay": case "gDay": case "gMonth":\r
149                         case "boolean":\r
150                         case "base64Binary": case "hexBinary":\r
151                         case "float": case "double":\r
152                         case "anyURI":\r
153                         case "QName":\r
154                         case "NOTATION":\r
155                         case "string": case "normalizedString": case "token":\r
156                         case "language": case "Name": case "NCName":\r
157                         case "ID": case "IDREF": case "IDREFS":\r
158                         case "ENTITY": case "ENTITIES":\r
159                         case "NMTOKEN": case "NMTOKENS":\r
160                         case "decimal": case "integer":\r
161                         case "nonPositiveInteger": case "negativeInteger":\r
162                         case "nonNegativeInteger":\r
163                         case "unsignedLong": case "unsignedInt":\r
164                         case "unsignedShort": case "unsignedByte":\r
165                         case "positiveInteger":\r
166                         case "long": case "int": case "short": case "byte":\r
167                                 return true;\r
168                         }\r
169                         return false;\r
170                 }\r
171 \r
172                 public static bool IsSchemaDatatypeEquals (XsdAnySimpleType st1, object v1,
173                         XsdAnySimpleType st2, object v2)
174                 {\r
175                         if (v1 == null || v2 == null)
176                                 return false;
177
178                         if (st1 == null)
179                                 st1 = XmlSchemaSimpleType.AnySimpleType;
180                         if (st2 == null)
181                                 st2 = XmlSchemaSimpleType.AnySimpleType;
182
183                         Type t = st2.GetType ();
184                         if (st1 is XsdFloat) {
185                                 return st2 is XsdFloat && Convert.ToSingle (v1) == Convert.ToSingle (v2);
186                         } else if (st1 is XsdDouble) {
187                                 return st2 is XsdDouble && Convert.ToDouble (v1) == Convert.ToDouble (v2);
188                         } else if (st1 is XsdDecimal) {
189                                 if (!(st2 is XsdDecimal) || Convert.ToDecimal (v1) != Convert.ToDecimal (v2))
190                                         return false;
191                                 if (st1 is XsdNonPositiveInteger)
192                                         return st2 is XsdNonPositiveInteger || t == typeof (XsdDecimal) || t == typeof (XsdInteger);
193                                 else if (st1 is XsdPositiveInteger)
194                                         return st2 is XsdPositiveInteger || t == typeof (XsdDecimal) || 
195                                                 t == typeof (XsdInteger) || t == typeof (XsdNonNegativeInteger);
196                                 else if (st1 is XsdUnsignedLong)
197                                         return st2 is XsdUnsignedLong || t == typeof (XsdDecimal) || 
198                                                 t == typeof (XsdInteger) || t == typeof (XsdNonNegativeInteger);
199                                 else if (st1 is XsdNonNegativeInteger)
200                                         return st2 is XsdNonNegativeInteger || t == typeof (XsdDecimal) || t == typeof (XsdInteger);
201                                 else if (st1 is XsdLong)
202                                         return st2 is XsdLong || t == typeof (XsdDecimal) || t == typeof (XsdInteger);
203                                 return true;
204                         }
205                         else if (!v1.Equals (v2))
206                                 return false;
207                         if (st1 is XsdString) {
208                                 if (!(st2 is XsdString))
209                                         return false;
210                                 if (st1 is XsdNMToken && (st2 is XsdLanguage || st2 is XsdName))
211                                         return false;
212                                 if (st2 is XsdNMToken && (st1 is XsdLanguage || st1 is XsdName))
213                                         return false;
214                                 if (st1 is XsdName && (st2 is XsdLanguage || st2 is XsdNMToken))
215                                         return false;
216                                 if (st2 is XsdName && (st1 is XsdLanguage || st1 is XsdNMToken))
217                                         return false;
218                                 if (st1 is XsdID && st2 is XsdIDRef)
219                                         return false;
220                                 if (st1 is XsdIDRef && st2 is XsdID)
221                                         return false;
222                         }
223                         else if (st1 != st2)
224                                 return false;
225                         return true;
226                 }
227 \r
228                 public static bool IsValidQName(string qname)\r
229                 {\r
230                         foreach(string part in qname.Split(new char[]{':'},2))\r
231                         {\r
232                                 if(!CheckNCName(part))\r
233                                         return false;\r
234                         }\r
235                         return true;\r
236                 }\r
237 \r
238                 //FIXME: First remove all the multiple instances of whitespace and then return the strings.\r
239                 //The current method returns empty strings if there are two or more consecutive whitespaces.\r
240                 public static string[] SplitList(string list)\r
241                 {\r
242                         if(list == null || list == string.Empty)\r
243                                 return new string [0];\r
244 \r
245                         ArrayList al = null;\r
246                         int start = 0;\r
247                         bool wait = true;\r
248                         for (int i = 0; i < list.Length; i++) {\r
249                                 switch (list [i]) {\r
250                                 case ' ':\r
251                                 case '\r':\r
252                                 case '\n':\r
253                                 case '\t':\r
254                                         if (!wait) {\r
255                                                 if (al == null)\r
256                                                         al = new ArrayList ();\r
257                                                 al.Add (list.Substring (start, i - start));\r
258                                         }\r
259                                         wait = true;\r
260                                         break;\r
261                                 default:\r
262                                         if (wait) {\r
263                                                 wait = false;\r
264                                                 start = i;\r
265                                         }\r
266                                         break;\r
267                                 }\r
268                         }\r
269 \r
270                         if (!wait && start == 0)\r
271                                 return new string [] {list};\r
272 \r
273                         if (!wait && start < list.Length)\r
274                                 al.Add (start == 0 ? list : list.Substring (start));\r
275                         return al.ToArray (typeof (string)) as string [];\r
276                 }\r
277 \r
278                 public static void ReadUnhandledAttribute(XmlReader reader, XmlSchemaObject xso)\r
279                 {\r
280                         if(reader.Prefix == "xmlns")\r
281                                 xso.Namespaces.Add(reader.LocalName, reader.Value);\r
282                         else if(reader.Name == "xmlns")\r
283                                 xso.Namespaces.Add("",reader.Value);\r
284                         else\r
285                         {\r
286                                 if(xso.unhandledAttributeList == null)\r
287                                         xso.unhandledAttributeList = new System.Collections.ArrayList();\r
288                                 XmlAttribute attr = new XmlDocument().CreateAttribute(reader.LocalName,reader.NamespaceURI);\r
289                                 attr.Value = reader.Value;\r
290                                 ParseWsdlArrayType (reader, attr);\r
291                                 xso.unhandledAttributeList.Add(attr);\r
292                         }\r
293                 }\r
294                 \r
295                 static void ParseWsdlArrayType (XmlReader reader, XmlAttribute attr)\r
296                 {\r
297                         if (attr.NamespaceURI == XmlSerializer.WsdlNamespace && attr.LocalName == "arrayType")\r
298                         {\r
299                                 string ns = "", type, dimensions;\r
300                                 TypeTranslator.ParseArrayType (attr.Value, out type, out ns, out dimensions);\r
301                                 if (ns != "") ns = reader.LookupNamespace (ns) + ":";\r
302                                 attr.Value = ns + type + dimensions;\r
303                         }\r
304                 }\r
305 \r
306                 public static bool ReadBoolAttribute(XmlReader reader, out Exception innerExcpetion)\r
307                 {\r
308                         innerExcpetion = null;\r
309                         try\r
310                         {\r
311                                 bool val = XmlConvert.ToBoolean(reader.Value);\r
312                                 return val;\r
313                         }\r
314                         catch(Exception ex)\r
315                         {\r
316                                 innerExcpetion = ex;\r
317                                 return false;\r
318                         }\r
319                 }\r
320                 public static decimal ReadDecimalAttribute(XmlReader reader,  out Exception innerExcpetion)\r
321                 {\r
322                         innerExcpetion = null;\r
323                         try\r
324                         {\r
325                                 decimal val = XmlConvert.ToDecimal(reader.Value);\r
326                                 return val;\r
327                         }\r
328                         catch(Exception ex)\r
329                         {\r
330                                 innerExcpetion = ex;\r
331                                 return decimal.Zero;\r
332                         }\r
333                 }\r
334 \r
335                 // Is some value is read, return it.\r
336                 // If no values return empty.\r
337                 // If exception, return none\r
338                 public static XmlSchemaDerivationMethod ReadDerivationAttribute(XmlReader reader, out Exception innerExcpetion, string name, XmlSchemaDerivationMethod allowed)\r
339                 {\r
340                         innerExcpetion = null;\r
341                         try\r
342                         {\r
343                                 string list = reader.Value;\r
344                                 string warn = "";\r
345                                 XmlSchemaDerivationMethod val = 0;\r
346                                 \r
347                                 if(list.IndexOf("#all") != -1 && list.Trim() != "#all")\r
348                                 {\r
349                                         innerExcpetion = new Exception(list+" is not a valid value for "+ name +". #all if present must be the only value");\r
350                                         return XmlSchemaDerivationMethod.All;\r
351                                 }\r
352                                 foreach(string xsdm in XmlSchemaUtil.SplitList(list))\r
353                                 {\r
354                                         switch(xsdm)\r
355                                         {\r
356                                                 case "":\r
357                                                         val = AddFlag (val, XmlSchemaDerivationMethod.Empty, allowed); break;\r
358                                                 case "#all":\r
359                                                         val = AddFlag (val,XmlSchemaDerivationMethod.All, allowed); break;\r
360                                                 case "substitution":\r
361                                                         val = AddFlag (val,XmlSchemaDerivationMethod.Substitution, allowed); break;\r
362                                                 case "extension":\r
363                                                         val = AddFlag (val,XmlSchemaDerivationMethod.Extension, allowed); break;\r
364                                                 case "restriction":\r
365                                                         val = AddFlag (val,XmlSchemaDerivationMethod.Restriction, allowed); break;\r
366                                                 case "list":\r
367                                                         val = AddFlag (val,XmlSchemaDerivationMethod.List, allowed); break;\r
368                                                 case "union":\r
369                                                         val = AddFlag (val,XmlSchemaDerivationMethod.Union, allowed); break;\r
370                                                 default:\r
371                                                         warn += xsdm + " "; break;\r
372                                         }\r
373                                 }\r
374                                 if(warn != "")\r
375                                                 innerExcpetion = new Exception(warn + "is/are not valid values for " + name);\r
376                                 return val;\r
377                         }\r
378                         catch(Exception ex)\r
379                         {\r
380                                 innerExcpetion = ex;\r
381                                 return XmlSchemaDerivationMethod.None;\r
382                         }\r
383                 }\r
384 \r
385                 private static XmlSchemaDerivationMethod AddFlag (XmlSchemaDerivationMethod dst,\r
386                         XmlSchemaDerivationMethod add, XmlSchemaDerivationMethod allowed)\r
387                 {\r
388                         if ((add & allowed) == 0 && allowed != XmlSchemaDerivationMethod.All)\r
389                                 throw new ArgumentException (add + " is not allowed in this attribute.");\r
390                         if ((dst & add) != 0)\r
391                                 throw new ArgumentException (add + " is already specified in this attribute.");\r
392                         return dst | add;\r
393                 }\r
394 \r
395                 public static XmlSchemaForm ReadFormAttribute(XmlReader reader, out Exception innerExcpetion)\r
396                 {\r
397                         innerExcpetion = null;\r
398                         XmlSchemaForm val = XmlSchemaForm.None;\r
399                         switch(reader.Value)\r
400                         {\r
401                                 case "qualified":\r
402                                         val = XmlSchemaForm.Qualified; break;\r
403                                 case "unqualified":\r
404                                         val = XmlSchemaForm.Unqualified; break;\r
405                                 default:\r
406                                         innerExcpetion = new Exception("only qualified or unqulified is a valid value"); break;\r
407                         }\r
408                         return val;\r
409                 }\r
410 \r
411                 public static XmlSchemaContentProcessing ReadProcessingAttribute(XmlReader reader, out Exception innerExcpetion)\r
412                 {\r
413                         innerExcpetion = null;\r
414                         XmlSchemaContentProcessing val = XmlSchemaContentProcessing.None;\r
415                         switch(reader.Value)\r
416                         {\r
417                                 case "lax":\r
418                                         val = XmlSchemaContentProcessing.Lax; break;\r
419                                 case "strict":\r
420                                         val = XmlSchemaContentProcessing.Strict; break;\r
421                                 case "skip":\r
422                                         val = XmlSchemaContentProcessing.Skip; break;\r
423                                 default:\r
424                                         innerExcpetion = new Exception("only lax , strict or skip are valid values for processContents");\r
425                                         break;\r
426                         }\r
427                         return val;\r
428                 }\r
429 \r
430                 public static XmlSchemaUse ReadUseAttribute(XmlReader reader, out Exception innerExcpetion)\r
431                 {\r
432                         innerExcpetion = null;\r
433                         XmlSchemaUse val = XmlSchemaUse.None;\r
434                         switch(reader.Value)\r
435                         {\r
436                                 case "optional":\r
437                                         val = XmlSchemaUse.Optional; break;\r
438                                 case "prohibited":\r
439                                         val = XmlSchemaUse.Prohibited; break;\r
440                                 case "required":\r
441                                         val = XmlSchemaUse.Required; break;\r
442                                 default:\r
443                                         innerExcpetion = new Exception("only optional , prohibited or required are valid values for use");\r
444                                         break;\r
445                         }\r
446                         return val;\r
447                 }\r
448                 public static XmlQualifiedName ReadQNameAttribute(XmlReader reader, out Exception innerEx)\r
449                 {\r
450                         return ToQName(reader, reader.Value, out innerEx);\r
451                 }\r
452 \r
453                 //While Creating a XmlQualifedName, we should check:\r
454                 // 1. If a prefix is present, its namespace should be resolvable.\r
455                 // 2. If a prefix is not present, and if the defaultNamespace is set, \r
456                 public static XmlQualifiedName ToQName(XmlReader reader, string qnamestr, out Exception innerEx)\r
457                 {\r
458 \r
459                         string ns;\r
460                         string name;\r
461                         XmlQualifiedName qname;\r
462                         innerEx = null;\r
463                         \r
464                         if(!IsValidQName(qnamestr))\r
465                         {\r
466                                 innerEx = new Exception(qnamestr + " is an invalid QName. Either name or namespace is not a NCName");\r
467                                 return XmlQualifiedName.Empty;\r
468                         }\r
469 \r
470                         string[] values = qnamestr.Split(new char[]{':'},2);\r
471 \r
472                         if(values.Length == 2)\r
473                         {\r
474                                 ns = reader.LookupNamespace(values[0]);\r
475                                 if(ns == null)\r
476                                 {\r
477                                         innerEx = new Exception("Namespace Prefix '"+values[0]+"could not be resolved");\r
478                                         return XmlQualifiedName.Empty;\r
479                                 }\r
480                                 name = values[1];\r
481                         }\r
482                         else\r
483                         {\r
484                                 //Default Namespace\r
485                                 ns = reader.LookupNamespace("");\r
486                                 name = values[0];\r
487                         }\r
488 \r
489                         qname = new XmlQualifiedName(name,ns);\r
490                         return qname;\r
491                 }\r
492 \r
493                 public static int ValidateAttributesResolved (\r
494                         XmlSchemaObjectTable attributesResolved,\r
495                         ValidationEventHandler h,\r
496                         XmlSchema schema,\r
497                         XmlSchemaObjectCollection attributes,\r
498                         XmlSchemaAnyAttribute anyAttribute,\r
499                         ref XmlSchemaAnyAttribute anyAttributeUse,\r
500                         XmlSchemaAttributeGroup redefined,\r
501                         bool skipEquivalent)\r
502                 {\r
503                         int errorCount = 0;\r
504                         if (anyAttribute != null && anyAttributeUse == null)\r
505                                 anyAttributeUse = anyAttribute;\r
506 \r
507                         ArrayList newAttrNames = new ArrayList ();\r
508 \r
509                         foreach (XmlSchemaObject xsobj in attributes) {\r
510                                 XmlSchemaAttributeGroupRef grpRef = xsobj as XmlSchemaAttributeGroupRef;\r
511                                 if (grpRef != null) {\r
512                                         // Resolve attributeGroup redefinition.\r
513                                         XmlSchemaAttributeGroup grp = null;\r
514                                         if (redefined != null && grpRef.RefName == redefined.QualifiedName)\r
515                                                 grp = redefined;\r
516                                         else\r
517                                                 grp = schema.AttributeGroups [grpRef.RefName] as XmlSchemaAttributeGroup;\r
518                                         // otherwise, it might be missing sub components.\r
519                                         if (grp == null) {\r
520                                                 if (!schema.missedSubComponents)// && schema.Schemas [grpRef.RefName.Namespace] != null)\r
521                                                         grpRef.error (h, "Referenced attribute group " + grpRef.RefName + " was not found in the corresponding schema.");\r
522                                                 continue;\r
523                                         }\r
524                                         if (grp.AttributeGroupRecursionCheck) {\r
525                                                 grp.error (h, "Attribute group recursion was found: " + grpRef.RefName);\r
526                                                 continue;\r
527                                         }\r
528                                         try {\r
529                                                 grp.AttributeGroupRecursionCheck = true;\r
530                                                 errorCount += grp.Validate (h, schema);\r
531                                         } finally {\r
532                                                 grp.AttributeGroupRecursionCheck = false;\r
533                                         }\r
534                                         if (grp.AnyAttributeUse != null) {\r
535                                                 if (anyAttribute == null)\r
536                                                         anyAttributeUse = grp.AnyAttributeUse;\r
537                                         }\r
538                                         foreach (DictionaryEntry entry in grp.AttributeUses) {\r
539                                                 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;\r
540 #if BUGGY_MS_COMPLIANT\r
541                                                 if (attr.Use == XmlSchemaUse.Prohibited)\r
542                                                         continue;\r
543 #endif\r
544                                                 if (attr.RefName != null && attr.RefName != XmlQualifiedName.Empty && (!skipEquivalent || !AreAttributesEqual (attr, attributesResolved [attr.RefName] as XmlSchemaAttribute)))\r
545                                                         AddToTable (attributesResolved, attr, attr.RefName, h);\r
546                                                 else if (!skipEquivalent || !AreAttributesEqual (attr, attributesResolved [attr.QualifiedName] as XmlSchemaAttribute))\r
547                                                         AddToTable (attributesResolved, attr, attr.QualifiedName, h);\r
548                                         }\r
549                                 } else {\r
550                                         XmlSchemaAttribute attr = xsobj as XmlSchemaAttribute;\r
551                                         if (attr != null) {\r
552                                                 errorCount += attr.Validate (h, schema);\r
553 \r
554                                                 if (newAttrNames.Contains (attr.QualifiedName))\r
555                                                         attr.error (h, String.Format ("Duplicate attributes was found for '{0}'", attr.QualifiedName));\r
556                                                 newAttrNames.Add (attr.QualifiedName);\r
557 \r
558 #if BUGGY_MS_COMPLIANT\r
559                                                 if (attr.Use == XmlSchemaUse.Prohibited)\r
560                                                         continue;\r
561 #endif\r
562                                                 if (attr.RefName != null && attr.RefName != XmlQualifiedName.Empty && (!skipEquivalent || !AreAttributesEqual (attr, attributesResolved [attr.RefName] as XmlSchemaAttribute)))\r
563                                                         AddToTable (attributesResolved, attr, attr.RefName, h);\r
564                                                 else if (!skipEquivalent || !AreAttributesEqual (attr, attributesResolved [attr.QualifiedName] as XmlSchemaAttribute))\r
565                                                         AddToTable (attributesResolved, attr, attr.QualifiedName, h);\r
566                                         } else {\r
567                                                 if (anyAttribute == null) {\r
568                                                         anyAttributeUse = (XmlSchemaAnyAttribute) xsobj;\r
569                                                         anyAttribute.Validate (h, schema);\r
570                                                 }\r
571                                         }\r
572                                 }\r
573                         }\r
574                         return errorCount;\r
575                 }\r
576 \r
577                 internal static bool AreAttributesEqual (XmlSchemaAttribute one,\r
578                         XmlSchemaAttribute another)\r
579                 {\r
580                         if (one == null || another == null)\r
581                                 return false;\r
582                         return one.AttributeType == another.AttributeType &&\r
583                                 one.Form == another.Form &&\r
584                                 one.ValidatedUse == another.ValidatedUse &&\r
585                                 one.ValidatedDefaultValue == another.ValidatedDefaultValue &&\r
586                                 one.ValidatedFixedValue == another.ValidatedFixedValue;\r
587                 }\r
588 \r
589 #if NET_2_0\r
590                 public static object ReadTypedValue (XmlReader reader,\r
591                         object type, IXmlNamespaceResolver nsResolver,\r
592                         StringBuilder tmpBuilder)\r
593 #else\r
594                 public static object ReadTypedValue (XmlReader reader,\r
595                         object type, XmlNamespaceManager nsResolver,\r
596                         StringBuilder tmpBuilder)\r
597 #endif\r
598                 {\r
599                         if (tmpBuilder == null)\r
600                                 tmpBuilder = new StringBuilder ();\r
601                         XmlSchemaDatatype dt = type as XmlSchemaDatatype;\r
602                         XmlSchemaSimpleType st = type as XmlSchemaSimpleType;\r
603                         if (st != null)\r
604                                 dt = st.Datatype;\r
605                         if (dt == null)\r
606                                 return null;\r
607 \r
608                         switch (reader.NodeType) {\r
609                         case XmlNodeType.Element:\r
610                                 if (reader.IsEmptyElement)\r
611                                         return null;\r
612 \r
613                                 tmpBuilder.Length = 0;\r
614                                 bool loop = true;\r
615                                 do {\r
616                                         reader.Read ();\r
617                                         switch (reader.NodeType) {\r
618                                         case XmlNodeType.SignificantWhitespace:\r
619                                         case XmlNodeType.Text:\r
620                                         case XmlNodeType.CDATA:\r
621                                                 tmpBuilder.Append (reader.Value);\r
622                                                 break;\r
623                                         case XmlNodeType.Comment:\r
624                                                 break;\r
625                                         default:\r
626                                                 loop = false;\r
627                                                 break;\r
628                                         }\r
629                                 } while (loop && !reader.EOF && reader.ReadState == ReadState.Interactive);\r
630                                 return dt.ParseValue (tmpBuilder.ToString (), reader.NameTable, nsResolver);\r
631                         case XmlNodeType.Attribute:\r
632                                 return dt.ParseValue (reader.Value, reader.NameTable, nsResolver);\r
633                         }\r
634                         return null;\r
635                 }\r
636 \r
637                 public static XmlSchemaObject FindAttributeDeclaration (\r
638                         string ns,\r
639                         XmlSchemaSet schemas,\r
640                         XmlSchemaComplexType cType,\r
641                         XmlQualifiedName qname)\r
642                 {\r
643                         XmlSchemaObject result = cType.AttributeUses [qname];\r
644                         if (result != null)\r
645                                 return result;\r
646                         if (cType.AttributeWildcard == null)\r
647                                 return null;\r
648 \r
649                         if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname, ns))\r
650                                 return null;\r
651 \r
652                         if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)\r
653                                 return cType.AttributeWildcard;\r
654                         XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;\r
655                         if (attr != null)\r
656                                 return attr;\r
657                         if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)\r
658                                 return cType.AttributeWildcard;\r
659                         else\r
660                                 return null;\r
661                 }\r
662 \r
663                 // Spec 3.10.4 Item Valid (Wildcard)\r
664                 private static bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname, string ns)\r
665                 {\r
666                         if (anyAttr.HasValueAny)\r
667                                 return true;\r
668                         if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || ns != anyAttr.TargetNamespace))\r
669                                 return true;\r
670                         if (anyAttr.HasValueTargetNamespace && ns == anyAttr.TargetNamespace)\r
671                                 return true;\r
672                         if (anyAttr.HasValueLocal && ns == "")\r
673                                 return true;\r
674                         for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)\r
675                                 if (anyAttr.ResolvedNamespaces [i] == ns)\r
676                                         return true;\r
677                         return false;\r
678                 }\r
679         }\r
680 }