Add MIT license to System.XML.DLL
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaSequence.cs
1 //\r
2 // System.Xml.Schema.XmlSchemaSequence.cs\r
3 //\r
4 // Author:\r
5 //      Dwivedi, Ajay kumar  Adwiv@Yahoo.com\r
6 //      Atsushi Enomoto  ginga@kit.hi-ho.ne.jp\r
7 //\r
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;\r
30 using System.Collections;\r
31 using System.Xml.Serialization;\r
32 using System.Xml;\r
33 \r
34 namespace System.Xml.Schema\r
35 {\r
36         /// <summary>\r
37         /// Summary description for XmlSchemaSequence.\r
38         /// </summary>\r
39         public class XmlSchemaSequence : XmlSchemaGroupBase\r
40         {\r
41                 private XmlSchemaObjectCollection items;\r
42                 const string xmlname = "sequence";\r
43 \r
44                 public XmlSchemaSequence()\r
45                 {\r
46                         items = new XmlSchemaObjectCollection();\r
47                 }\r
48 \r
49                 [XmlElement("element",typeof(XmlSchemaElement),Namespace="http://www.w3.org/2001/XMLSchema")]\r
50                 [XmlElement("group",typeof(XmlSchemaGroupRef),Namespace="http://www.w3.org/2001/XMLSchema")]\r
51                 [XmlElement("choice",typeof(XmlSchemaChoice),Namespace="http://www.w3.org/2001/XMLSchema")]\r
52                 [XmlElement("sequence",typeof(XmlSchemaSequence),Namespace="http://www.w3.org/2001/XMLSchema")]\r
53                 [XmlElement("any",typeof(XmlSchemaAny),Namespace="http://www.w3.org/2001/XMLSchema")]\r
54                 public override XmlSchemaObjectCollection Items \r
55                 {\r
56                         get{ return items; }\r
57                 }\r
58 \r
59                 internal override int Compile(ValidationEventHandler h, XmlSchema schema)\r
60                 {\r
61                         // If this is already compiled this time, simply skip.\r
62                         if (this.IsComplied (schema.CompilationId))\r
63                                 return 0;\r
64 \r
65                         XmlSchemaUtil.CompileID(Id, this, schema.IDCollection, h);\r
66                         CompileOccurence (h, schema);\r
67 \r
68                         foreach(XmlSchemaObject obj in Items)\r
69                         {\r
70                                 if(obj is XmlSchemaElement ||\r
71                                         obj is XmlSchemaGroupRef ||\r
72                                         obj is XmlSchemaChoice ||\r
73                                         obj is XmlSchemaSequence ||\r
74                                         obj is XmlSchemaAny)\r
75                                 {\r
76                                         errorCount += obj.Compile(h,schema);\r
77                                 }\r
78                                 else\r
79                                         error(h, "Invalid schema object was specified in the particles of the sequence model group.");\r
80                         }\r
81                         this.CompilationId = schema.CompilationId;\r
82                         return errorCount;\r
83                 }\r
84 \r
85 \r
86                 internal override XmlSchemaParticle GetOptimizedParticle (bool isTop)\r
87                 {\r
88                         if (OptimizedParticle != null)\r
89                                 return OptimizedParticle;\r
90                         if (Items.Count == 0 || ValidatedMaxOccurs == 0) {\r
91                                 OptimizedParticle = XmlSchemaParticle.Empty;\r
92                                 return OptimizedParticle;\r
93                         }\r
94                         if (!isTop && ValidatedMinOccurs == 1 && ValidatedMaxOccurs == 1) {\r
95                                 if (Items.Count == 1)\r
96                                         return ((XmlSchemaParticle) Items [0]).GetOptimizedParticle (false);\r
97                         }\r
98 \r
99                         XmlSchemaSequence seq = new XmlSchemaSequence ();\r
100                         CopyInfo (seq);\r
101                         for (int i = 0; i < Items.Count; i++) {\r
102                                 XmlSchemaParticle p = Items [i] as XmlSchemaParticle;\r
103                                 p = p.GetOptimizedParticle (false);\r
104                                 if (p == XmlSchemaParticle.Empty)\r
105                                         continue;\r
106 \r
107                                 else if (p is XmlSchemaSequence && p.ValidatedMinOccurs == 1 && p.ValidatedMaxOccurs == 1) {\r
108                                         XmlSchemaSequence ps = p as XmlSchemaSequence;\r
109                                         for (int pi = 0; pi < ps.Items.Count; pi++) {\r
110                                                 seq.Items.Add (ps.Items [pi]);\r
111                                                 seq.CompiledItems.Add (ps.Items [pi]);\r
112                                         }\r
113                                 }\r
114                                 else {\r
115                                         seq.Items.Add (p);\r
116                                         seq.CompiledItems.Add (p);\r
117                                 }\r
118                         }\r
119                         if (seq.Items.Count == 0)\r
120                                 OptimizedParticle = XmlSchemaParticle.Empty;\r
121                         else\r
122                                 OptimizedParticle = seq;\r
123                         return OptimizedParticle;\r
124                 }\r
125 \r
126                 internal override int Validate (ValidationEventHandler h, XmlSchema schema)\r
127                 {\r
128                         if (IsValidated (schema.CompilationId))\r
129                                 return errorCount;\r
130 \r
131                         CompiledItems.Clear ();\r
132                         foreach (XmlSchemaParticle p in Items) {\r
133                                 errorCount += p.Validate (h, schema); // This is basically extraneous for pointless item, but needed to check validation error.\r
134 //                              XmlSchemaParticle particleInPoint = p.GetParticleWithoutPointless ();\r
135 //                              if (particleInPoint != XmlSchemaParticle.Empty)\r
136 //                                      CompiledItems.Add (particleInPoint);\r
137                                 CompiledItems.Add (p);\r
138                         }\r
139 \r
140                         ValidationId = schema.ValidationId;\r
141                         return errorCount;\r
142                 }\r
143 \r
144                 internal override bool ValidateDerivationByRestriction (XmlSchemaParticle baseParticle,\r
145                         ValidationEventHandler h, XmlSchema schema, bool raiseError)\r
146                 {\r
147                         if (this == baseParticle) // quick check\r
148                                 return true;\r
149 \r
150                         XmlSchemaElement el = baseParticle as XmlSchemaElement;\r
151                         if (el != null) {\r
152                                 // Forbidden\r
153                                 if (raiseError)\r
154                                         error (h, "Invalid sequence paricle derivation.");\r
155                                 return false;\r
156                         }\r
157 \r
158                         XmlSchemaSequence seq = baseParticle as XmlSchemaSequence;\r
159                         if (seq != null) {\r
160                                 // Recurse\r
161                                 if (!ValidateOccurenceRangeOK (seq, h, schema, raiseError))\r
162                                         return false;\r
163 \r
164                                 // If it is totally optional, then ignore their contents.\r
165                                 if (seq.ValidatedMinOccurs == 0 && seq.ValidatedMaxOccurs == 0 &&\r
166                                         this.ValidatedMinOccurs == 0 && this.ValidatedMaxOccurs == 0)\r
167                                         return true;\r
168                                 return ValidateRecurse (seq, h, schema, raiseError);\r
169                         } \r
170 \r
171                         XmlSchemaAll all = baseParticle as XmlSchemaAll;\r
172                         if (all != null) {\r
173                                 // RecurseUnordered\r
174                                 XmlSchemaObjectCollection already = new XmlSchemaObjectCollection ();\r
175                                 for (int i = 0; i < this.Items.Count; i++) {\r
176                                         XmlSchemaElement de = this.Items [i] as XmlSchemaElement;\r
177                                         if (de == null) {\r
178                                                 if (raiseError)\r
179                                                         error (h, "Invalid sequence particle derivation by restriction from all.");\r
180                                                 return false;\r
181                                         }\r
182                                         foreach (XmlSchemaElement e in all.Items) {\r
183                                                 if (e.QualifiedName == de.QualifiedName) {\r
184                                                         if (already.Contains (e)) {\r
185                                                                 if (raiseError)\r
186                                                                         error (h, "Base element particle is mapped to the derived element particle in a sequence two or more times.");\r
187                                                                 return false;\r
188                                                         } else {\r
189                                                                 already.Add (e);\r
190                                                                 if (!de.ValidateDerivationByRestriction (e, h, schema, raiseError))\r
191                                                                         return false;\r
192                                                         }\r
193                                                 }\r
194                                         }\r
195                                 }\r
196                                 foreach (XmlSchemaElement e in all.Items)\r
197                                         if (!already.Contains (e))\r
198                                                 if (!e.ValidateIsEmptiable ()) {\r
199                                                         if (raiseError)\r
200                                                                 error (h, "In base -all- particle, mapping-skipped base element which is not emptiable was found.");\r
201                                                         return false;\r
202                                                 }\r
203                                 return true;\r
204                         }\r
205                         XmlSchemaAny any = baseParticle as XmlSchemaAny;\r
206                         if (any != null) {\r
207                                 // NSRecurseCheckCardinality\r
208                                 return ValidateNSRecurseCheckCardinality (any, h, schema, raiseError);\r
209                         }\r
210                         XmlSchemaChoice choice = baseParticle as XmlSchemaChoice;\r
211                         if (choice != null) {\r
212                                 // MapAndSum\r
213                                 // In fact it is not Recurse, but it looks almost common.\r
214                                 return ValidateSeqRecurseMapSumCommon (choice, h, schema, false, true, raiseError);\r
215                         }\r
216                         return true;\r
217                 }\r
218 \r
219                 internal override decimal GetMinEffectiveTotalRange ()\r
220                 {\r
221                         return GetMinEffectiveTotalRangeAllAndSequence ();\r
222                 }\r
223 \r
224                 internal override void ValidateUniqueParticleAttribution (XmlSchemaObjectTable qnames, ArrayList nsNames,\r
225                         ValidationEventHandler h, XmlSchema schema)\r
226                 {\r
227                         foreach (XmlSchemaParticle p in this.Items) {\r
228                                 p.ValidateUniqueParticleAttribution (qnames, nsNames, h, schema);\r
229                                 if (p.ValidatedMinOccurs == p.ValidatedMaxOccurs)\r
230                                         break;\r
231                         }\r
232                         XmlSchemaObjectTable tmpTable = new XmlSchemaObjectTable ();\r
233                         ArrayList al = new ArrayList ();\r
234                         for (int i=0; i<Items.Count; i++) {\r
235                                 XmlSchemaParticle p1 = Items [i] as XmlSchemaParticle;\r
236                                 p1.ValidateUniqueParticleAttribution (tmpTable, al, h, schema);\r
237                                 if (p1.ValidatedMinOccurs == p1.ValidatedMaxOccurs) {\r
238                                         tmpTable.Clear ();\r
239                                         al.Clear ();\r
240                                 }\r
241                         }\r
242                 }\r
243 \r
244                 internal override void ValidateUniqueTypeAttribution (XmlSchemaObjectTable labels,\r
245                         ValidationEventHandler h, XmlSchema schema)\r
246                 {\r
247                         foreach (XmlSchemaParticle p in this.Items)\r
248                                 p.ValidateUniqueTypeAttribution (labels, h, schema);\r
249                 }\r
250 \r
251                 //<sequence\r
252                 //  id = ID\r
253                 //  maxOccurs =  (nonNegativeInteger | unbounded)  : 1\r
254                 //  minOccurs = nonNegativeInteger : 1\r
255                 //  {any attributes with non-schema namespace . . .}>\r
256                 //  Content: (annotation?, (element | group | choice | sequence | any)*)\r
257                 //</sequence>\r
258                 internal static XmlSchemaSequence Read(XmlSchemaReader reader, ValidationEventHandler h)\r
259                 {\r
260                         XmlSchemaSequence sequence = new XmlSchemaSequence();\r
261                         reader.MoveToElement();\r
262 \r
263                         if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname)\r
264                         {\r
265                                 error(h,"Should not happen :1: XmlSchemaSequence.Read, name="+reader.Name,null);\r
266                                 reader.Skip();\r
267                                 return null;\r
268                         }\r
269 \r
270                         sequence.LineNumber = reader.LineNumber;\r
271                         sequence.LinePosition = reader.LinePosition;\r
272                         sequence.SourceUri = reader.BaseURI;\r
273 \r
274                         while(reader.MoveToNextAttribute())\r
275                         {\r
276                                 if(reader.Name == "id")\r
277                                 {\r
278                                         sequence.Id = reader.Value;\r
279                                 }\r
280                                 else if(reader.Name == "maxOccurs")\r
281                                 {\r
282                                         try\r
283                                         {\r
284                                                 sequence.MaxOccursString = reader.Value;\r
285                                         }\r
286                                         catch(Exception e)\r
287                                         {\r
288                                                 error(h,reader.Value + " is an invalid value for maxOccurs",e);\r
289                                         }\r
290                                 }\r
291                                 else if(reader.Name == "minOccurs")\r
292                                 {\r
293                                         try\r
294                                         {\r
295                                                 sequence.MinOccursString = reader.Value;\r
296                                         }\r
297                                         catch(Exception e)\r
298                                         {\r
299                                                 error(h,reader.Value + " is an invalid value for minOccurs",e);\r
300                                         }\r
301                                 }\r
302                                 else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)\r
303                                 {\r
304                                         error(h,reader.Name + " is not a valid attribute for sequence",null);\r
305                                 }\r
306                                 else\r
307                                 {\r
308                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,sequence);\r
309                                 }\r
310                         }\r
311                         \r
312                         reader.MoveToElement();\r
313                         if(reader.IsEmptyElement)\r
314                                 return sequence;\r
315 \r
316                         //  Content: (annotation?, (element | group | choice | sequence | any)*)\r
317                         int level = 1;\r
318                         while(reader.ReadNextElement())\r
319                         {\r
320                                 if(reader.NodeType == XmlNodeType.EndElement)\r
321                                 {\r
322                                         if(reader.LocalName != xmlname)\r
323                                                 error(h,"Should not happen :2: XmlSchemaSequence.Read, name="+reader.Name,null);\r
324                                         break;\r
325                                 }\r
326                                 if(level <= 1 && reader.LocalName == "annotation")\r
327                                 {\r
328                                         level = 2; //Only one annotation\r
329                                         XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);\r
330                                         if(annotation != null)\r
331                                                 sequence.Annotation = annotation;\r
332                                         continue;\r
333                                 }\r
334                                 if(level <=2)\r
335                                 {\r
336                                         if(reader.LocalName == "element")\r
337                                         {\r
338                                                 level = 2;\r
339                                                 XmlSchemaElement element = XmlSchemaElement.Read(reader,h);\r
340                                                 if(element != null)\r
341                                                         sequence.items.Add(element);\r
342                                                 continue;\r
343                                         }\r
344                                         if(reader.LocalName == "group")\r
345                                         {\r
346                                                 level = 2;\r
347                                                 XmlSchemaGroupRef group = XmlSchemaGroupRef.Read(reader,h);\r
348                                                 if(group != null)\r
349                                                         sequence.items.Add(group);\r
350                                                 continue;\r
351                                         }\r
352                                         if(reader.LocalName == "choice")\r
353                                         {\r
354                                                 level = 2;\r
355                                                 XmlSchemaChoice choice = XmlSchemaChoice.Read(reader,h);\r
356                                                 if(choice != null)\r
357                                                         sequence.items.Add(choice);\r
358                                                 continue;\r
359                                         }\r
360                                         if(reader.LocalName == "sequence")\r
361                                         {\r
362                                                 level = 2;\r
363                                                 XmlSchemaSequence seq = XmlSchemaSequence.Read(reader,h);\r
364                                                 if(seq != null)\r
365                                                         sequence.items.Add(seq);\r
366                                                 continue;\r
367                                         }\r
368                                         if(reader.LocalName == "any")\r
369                                         {\r
370                                                 level = 2;\r
371                                                 XmlSchemaAny any = XmlSchemaAny.Read(reader,h);\r
372                                                 if(any != null)\r
373                                                         sequence.items.Add(any);\r
374                                                 continue;\r
375                                         }\r
376                                 }\r
377                                 reader.RaiseInvalidElementError();\r
378                         }\r
379                         return sequence;\r
380                 }\r
381         }\r
382 }\r