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