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