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