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