System.XML: added null arguments validation for targetType and namespaceResolver...
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaSequence.cs
1 //
2 // System.Xml.Schema.XmlSchemaSequence.cs
3 //
4 // Author:
5 //      Dwivedi, Ajay kumar  Adwiv@Yahoo.com
6 //      Atsushi Enomoto  ginga@kit.hi-ho.ne.jp
7 //
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Collections;
31 using System.Xml.Serialization;
32 using System.Xml;
33
34 namespace System.Xml.Schema
35 {
36         /// <summary>
37         /// Summary description for XmlSchemaSequence.
38         /// </summary>
39         public class XmlSchemaSequence : XmlSchemaGroupBase
40         {
41                 private XmlSchemaObjectCollection items;
42                 const string xmlname = "sequence";
43
44                 public XmlSchemaSequence()
45                 {
46                         items = new XmlSchemaObjectCollection();
47                 }
48
49                 [XmlElement("element",typeof(XmlSchemaElement))]
50                 [XmlElement("group",typeof(XmlSchemaGroupRef))]
51                 [XmlElement("choice",typeof(XmlSchemaChoice))]
52                 [XmlElement("sequence",typeof(XmlSchemaSequence))]
53                 [XmlElement("any",typeof(XmlSchemaAny))]
54                 public override XmlSchemaObjectCollection Items 
55                 {
56                         get{ return items; }
57                 }
58
59                 internal override void SetParent (XmlSchemaObject parent)
60                 {
61                         base.SetParent (parent);
62                         foreach (XmlSchemaObject obj in Items)
63                                 obj.SetParent (this);
64                 }
65
66                 internal override int Compile(ValidationEventHandler h, XmlSchema schema)
67                 {
68                         // If this is already compiled this time, simply skip.
69                         if (CompilationId == schema.CompilationId)
70                                 return 0;
71
72                         XmlSchemaUtil.CompileID(Id, this, schema.IDCollection, h);
73                         CompileOccurence (h, schema);
74
75                         foreach(XmlSchemaObject obj in Items)
76                         {
77                                 if(obj is XmlSchemaElement ||
78                                         obj is XmlSchemaGroupRef ||
79                                         obj is XmlSchemaChoice ||
80                                         obj is XmlSchemaSequence ||
81                                         obj is XmlSchemaAny)
82                                 {
83                                         errorCount += obj.Compile(h,schema);
84                                 }
85                                 else
86                                         error(h, "Invalid schema object was specified in the particles of the sequence model group.");
87                         }
88                         this.CompilationId = schema.CompilationId;
89                         return errorCount;
90                 }
91
92
93                 internal override XmlSchemaParticle GetOptimizedParticle (bool isTop)
94                 {
95                         if (OptimizedParticle != null)
96                                 return OptimizedParticle;
97                         if (Items.Count == 0 || ValidatedMaxOccurs == 0) {
98                                 OptimizedParticle = XmlSchemaParticle.Empty;
99                                 return OptimizedParticle;
100                         }
101                         if (!isTop && ValidatedMinOccurs == 1 && ValidatedMaxOccurs == 1) {
102                                 if (Items.Count == 1)
103                                         return ((XmlSchemaParticle) Items [0]).GetOptimizedParticle (false);
104                         }
105
106                         XmlSchemaSequence seq = new XmlSchemaSequence ();
107                         CopyInfo (seq);
108                         for (int i = 0; i < Items.Count; i++) {
109                                 XmlSchemaParticle p = Items [i] as XmlSchemaParticle;
110                                 p = p.GetOptimizedParticle (false);
111                                 if (p == XmlSchemaParticle.Empty)
112                                         continue;
113
114                                 else if (p is XmlSchemaSequence && p.ValidatedMinOccurs == 1 && p.ValidatedMaxOccurs == 1) {
115                                         XmlSchemaSequence ps = p as XmlSchemaSequence;
116                                         for (int pi = 0; pi < ps.Items.Count; pi++) {
117                                                 seq.Items.Add (ps.Items [pi]);
118                                                 seq.CompiledItems.Add (ps.Items [pi]);
119                                         }
120                                 }
121                                 else {
122                                         seq.Items.Add (p);
123                                         seq.CompiledItems.Add (p);
124                                 }
125                         }
126                         if (seq.Items.Count == 0)
127                                 OptimizedParticle = XmlSchemaParticle.Empty;
128                         else
129                                 OptimizedParticle = seq;
130                         return OptimizedParticle;
131                 }
132
133                 internal override int Validate (ValidationEventHandler h, XmlSchema schema)
134                 {
135                         if (IsValidated (schema.CompilationId))
136                                 return errorCount;
137
138                         CompiledItems.Clear ();
139                         foreach (XmlSchemaParticle p in Items) {
140                                 errorCount += p.Validate (h, schema); // This is basically extraneous for pointless item, but needed to check validation error.
141 //                              XmlSchemaParticle particleInPoint = p.GetParticleWithoutPointless ();
142 //                              if (particleInPoint != XmlSchemaParticle.Empty)
143 //                                      CompiledItems.Add (particleInPoint);
144                                 CompiledItems.Add (p);
145                         }
146
147                         ValidationId = schema.ValidationId;
148                         return errorCount;
149                 }
150
151                 internal override bool ValidateDerivationByRestriction (XmlSchemaParticle baseParticle,
152                         ValidationEventHandler h, XmlSchema schema, bool raiseError)
153                 {
154                         if (this == baseParticle) // quick check
155                                 return true;
156
157                         XmlSchemaElement el = baseParticle as XmlSchemaElement;
158                         if (el != null) {
159                                 // Forbidden
160                                 if (raiseError)
161                                         error (h, "Invalid sequence paricle derivation.");
162                                 return false;
163                         }
164
165                         XmlSchemaSequence seq = baseParticle as XmlSchemaSequence;
166                         if (seq != null) {
167                                 // Recurse
168                                 if (!ValidateOccurenceRangeOK (seq, h, schema, raiseError))
169                                         return false;
170
171                                 // If it is totally optional, then ignore their contents.
172                                 if (seq.ValidatedMinOccurs == 0 && seq.ValidatedMaxOccurs == 0 &&
173                                         this.ValidatedMinOccurs == 0 && this.ValidatedMaxOccurs == 0)
174                                         return true;
175                                 return ValidateRecurse (seq, h, schema, raiseError);
176                         } 
177
178                         XmlSchemaAll all = baseParticle as XmlSchemaAll;
179                         if (all != null) {
180                                 // RecurseUnordered
181                                 XmlSchemaObjectCollection already = new XmlSchemaObjectCollection ();
182                                 for (int i = 0; i < this.Items.Count; i++) {
183                                         XmlSchemaElement de = this.Items [i] as XmlSchemaElement;
184                                         if (de == null) {
185                                                 if (raiseError)
186                                                         error (h, "Invalid sequence particle derivation by restriction from all.");
187                                                 return false;
188                                         }
189                                         foreach (XmlSchemaElement e in all.Items) {
190                                                 if (e.QualifiedName == de.QualifiedName) {
191                                                         if (already.Contains (e)) {
192                                                                 if (raiseError)
193                                                                         error (h, "Base element particle is mapped to the derived element particle in a sequence two or more times.");
194                                                                 return false;
195                                                         } else {
196                                                                 already.Add (e);
197                                                                 if (!de.ValidateDerivationByRestriction (e, h, schema, raiseError))
198                                                                         return false;
199                                                         }
200                                                 }
201                                         }
202                                 }
203                                 foreach (XmlSchemaElement e in all.Items)
204                                         if (!already.Contains (e))
205                                                 if (!e.ValidateIsEmptiable ()) {
206                                                         if (raiseError)
207                                                                 error (h, "In base -all- particle, mapping-skipped base element which is not emptiable was found.");
208                                                         return false;
209                                                 }
210                                 return true;
211                         }
212                         XmlSchemaAny any = baseParticle as XmlSchemaAny;
213                         if (any != null) {
214                                 // NSRecurseCheckCardinality
215                                 return ValidateNSRecurseCheckCardinality (any, h, schema, raiseError);
216                         }
217                         XmlSchemaChoice choice = baseParticle as XmlSchemaChoice;
218                         if (choice != null) {
219                                 // MapAndSum
220                                 // In fact it is not Recurse, but it looks almost common.
221                                 return ValidateSeqRecurseMapSumCommon (choice, h, schema, false, true, raiseError);
222                         }
223                         return true;
224                 }
225
226                 internal override decimal GetMinEffectiveTotalRange ()
227                 {
228                         return GetMinEffectiveTotalRangeAllAndSequence ();
229                 }
230
231                 internal override void ValidateUniqueParticleAttribution (XmlSchemaObjectTable qnames, ArrayList nsNames,
232                         ValidationEventHandler h, XmlSchema schema)
233                 {
234                         ValidateUPAOnHeadingOptionalComponents (qnames, nsNames, h, schema);
235                         ValidateUPAOnItems (qnames, nsNames, h, schema);
236                 }
237
238                 void ValidateUPAOnHeadingOptionalComponents (XmlSchemaObjectTable qnames, ArrayList nsNames,
239                         ValidationEventHandler h, XmlSchema schema)
240                 {
241                         // heading optional components
242                         foreach (XmlSchemaParticle p in this.Items) {
243                                 p.ValidateUniqueParticleAttribution (qnames, nsNames, h, schema);
244                                 if (p.ValidatedMinOccurs != 0)
245                                         break;
246                         }
247                 }
248
249                 void ValidateUPAOnItems (XmlSchemaObjectTable qnames, ArrayList nsNames,
250                         ValidationEventHandler h, XmlSchema schema)
251                 {
252                         // non-optional components
253                         XmlSchemaObjectTable elems = new XmlSchemaObjectTable ();
254                         ArrayList wildcards = new ArrayList ();
255                         XmlSchemaObjectTable tmpElems = new XmlSchemaObjectTable ();
256                         ArrayList tmpWildcards = new ArrayList ();
257                         for (int i=0; i<Items.Count; i++) {
258                                 XmlSchemaParticle p1 = Items [i] as XmlSchemaParticle;
259                                 p1.ValidateUniqueParticleAttribution (elems, wildcards, h, schema);
260                                 if (p1.ValidatedMinOccurs == p1.ValidatedMaxOccurs) {
261                                         elems.Clear ();
262                                         wildcards.Clear ();
263                                 }
264                                 else {
265                                         if (p1.ValidatedMinOccurs != 0) {
266                                                 foreach (XmlQualifiedName n in tmpElems.Names)
267                                                         elems.Set (n, null); // remove
268                                                 foreach (object o in tmpWildcards)
269                                                         wildcards.Remove (o);
270                                         }
271                                         foreach (XmlQualifiedName n in elems.Names)
272                                                 tmpElems.Set (n, elems [n]);
273                                         tmpWildcards.Clear ();
274                                         tmpWildcards.AddRange (wildcards);
275                                 }
276                         }
277                 }
278
279                 internal override void ValidateUniqueTypeAttribution (XmlSchemaObjectTable labels,
280                         ValidationEventHandler h, XmlSchema schema)
281                 {
282                         foreach (XmlSchemaParticle p in this.Items)
283                                 p.ValidateUniqueTypeAttribution (labels, h, schema);
284                 }
285
286                 //<sequence
287                 //  id = ID
288                 //  maxOccurs =  (nonNegativeInteger | unbounded)  : 1
289                 //  minOccurs = nonNegativeInteger : 1
290                 //  {any attributes with non-schema namespace . . .}>
291                 //  Content: (annotation?, (element | group | choice | sequence | any)*)
292                 //</sequence>
293                 internal static XmlSchemaSequence Read(XmlSchemaReader reader, ValidationEventHandler h)
294                 {
295                         XmlSchemaSequence sequence = new XmlSchemaSequence();
296                         reader.MoveToElement();
297
298                         if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname)
299                         {
300                                 error(h,"Should not happen :1: XmlSchemaSequence.Read, name="+reader.Name,null);
301                                 reader.Skip();
302                                 return null;
303                         }
304
305                         sequence.LineNumber = reader.LineNumber;
306                         sequence.LinePosition = reader.LinePosition;
307                         sequence.SourceUri = reader.BaseURI;
308
309                         while(reader.MoveToNextAttribute())
310                         {
311                                 if(reader.Name == "id")
312                                 {
313                                         sequence.Id = reader.Value;
314                                 }
315                                 else if(reader.Name == "maxOccurs")
316                                 {
317                                         try
318                                         {
319                                                 sequence.MaxOccursString = reader.Value;
320                                         }
321                                         catch(Exception e)
322                                         {
323                                                 error(h,reader.Value + " is an invalid value for maxOccurs",e);
324                                         }
325                                 }
326                                 else if(reader.Name == "minOccurs")
327                                 {
328                                         try
329                                         {
330                                                 sequence.MinOccursString = reader.Value;
331                                         }
332                                         catch(Exception e)
333                                         {
334                                                 error(h,reader.Value + " is an invalid value for minOccurs",e);
335                                         }
336                                 }
337                                 else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)
338                                 {
339                                         error(h,reader.Name + " is not a valid attribute for sequence",null);
340                                 }
341                                 else
342                                 {
343                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,sequence);
344                                 }
345                         }
346                         
347                         reader.MoveToElement();
348                         if(reader.IsEmptyElement)
349                                 return sequence;
350
351                         //  Content: (annotation?, (element | group | choice | sequence | any)*)
352                         int level = 1;
353                         while(reader.ReadNextElement())
354                         {
355                                 if(reader.NodeType == XmlNodeType.EndElement)
356                                 {
357                                         if(reader.LocalName != xmlname)
358                                                 error(h,"Should not happen :2: XmlSchemaSequence.Read, name="+reader.Name,null);
359                                         break;
360                                 }
361                                 if(level <= 1 && reader.LocalName == "annotation")
362                                 {
363                                         level = 2; //Only one annotation
364                                         XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
365                                         if(annotation != null)
366                                                 sequence.Annotation = annotation;
367                                         continue;
368                                 }
369                                 if(level <=2)
370                                 {
371                                         if(reader.LocalName == "element")
372                                         {
373                                                 level = 2;
374                                                 XmlSchemaElement element = XmlSchemaElement.Read(reader,h);
375                                                 if(element != null)
376                                                         sequence.items.Add(element);
377                                                 continue;
378                                         }
379                                         if(reader.LocalName == "group")
380                                         {
381                                                 level = 2;
382                                                 XmlSchemaGroupRef group = XmlSchemaGroupRef.Read(reader,h);
383                                                 if(group != null)
384                                                         sequence.items.Add(group);
385                                                 continue;
386                                         }
387                                         if(reader.LocalName == "choice")
388                                         {
389                                                 level = 2;
390                                                 XmlSchemaChoice choice = XmlSchemaChoice.Read(reader,h);
391                                                 if(choice != null)
392                                                         sequence.items.Add(choice);
393                                                 continue;
394                                         }
395                                         if(reader.LocalName == "sequence")
396                                         {
397                                                 level = 2;
398                                                 XmlSchemaSequence seq = XmlSchemaSequence.Read(reader,h);
399                                                 if(seq != null)
400                                                         sequence.items.Add(seq);
401                                                 continue;
402                                         }
403                                         if(reader.LocalName == "any")
404                                         {
405                                                 level = 2;
406                                                 XmlSchemaAny any = XmlSchemaAny.Read(reader,h);
407                                                 if(any != null)
408                                                         sequence.items.Add(any);
409                                                 continue;
410                                         }
411                                 }
412                                 reader.RaiseInvalidElementError();
413                         }
414                         return sequence;
415                 }
416         }
417 }