2008-12-08 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaParticle.cs
1 // Author: Dwivedi, Ajay kumar
2 //            Adwiv@Yahoo.com
3
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 // 
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 // 
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 using System;
25 using System.Collections;
26 using System.Globalization;
27 using System.Xml.Serialization;
28
29 namespace System.Xml.Schema
30 {
31         /// <summary>
32         /// Summary description for XmlSchemaParticle.
33         /// </summary>
34         public abstract class XmlSchemaParticle : XmlSchemaAnnotated
35         {
36                 internal static XmlSchemaParticle Empty {
37                         get {
38                                 if (empty == null) {
39                                         empty = new EmptyParticle ();
40                                 }
41                                 return empty;
42                         }
43                 }
44
45                 decimal minOccurs, maxOccurs;
46                 string  minstr, maxstr;
47                 static XmlSchemaParticle empty;
48                 decimal validatedMinOccurs = 1, validatedMaxOccurs = 1;
49                 internal int recursionDepth = -1;
50                 private decimal minEffectiveTotalRange = -1;
51                 internal bool parentIsGroupDefinition;
52
53                 protected XmlSchemaParticle()
54                 {
55                         minOccurs = decimal.One;
56                         maxOccurs = decimal.One;
57                 }
58
59                 #region Attributes
60
61                 [System.Xml.Serialization.XmlAttribute("minOccurs")]
62                 public string MinOccursString
63                 {
64                         get{ return minstr; }
65                         set
66                         {
67                                 if (value == null) {
68                                         minOccurs = decimal.One;
69                                         minstr = value;
70                                         return;
71                                 }
72
73                                 decimal val = decimal.Parse (value, CultureInfo.InvariantCulture);
74                                 if(val >= 0 && (val == Decimal.Truncate(val)))
75                                 {
76                                         minOccurs = val;
77                                         minstr   = val.ToString (CultureInfo.InvariantCulture);
78                                 }
79                                 else
80                                 {
81                                         throw new XmlSchemaException
82                                                 ("MinOccursString must be a non-negative number",null);                                         
83                                 }
84                         }
85                 }
86
87                 [System.Xml.Serialization.XmlAttribute("maxOccurs")]
88                 public string MaxOccursString
89                 {
90                         get{ return maxstr; }
91                         set
92                         {
93                                 if(value == "unbounded")
94                                 {
95                                         maxstr = value;
96                                         maxOccurs = decimal.MaxValue;
97                                 }
98                                 else
99                                 {
100                                         decimal val = decimal.Parse (value, CultureInfo.InvariantCulture);
101                                         if(val >= 0 && (val == Decimal.Truncate(val)))
102                                         {
103                                                 maxOccurs = val;
104                                                 maxstr = val.ToString (CultureInfo.InvariantCulture);
105                                         }
106                                         else
107                                         {
108                                                 throw new XmlSchemaException
109                                                         ("MaxOccurs must be a non-negative integer",null);
110                                         }
111                                         if (val == 0 && minstr == null)
112                                                 minOccurs = 0;
113                                 }
114                         }
115                 }
116
117                 #endregion
118
119                 #region XmlIgnore
120
121                 [XmlIgnore]
122                 public decimal MinOccurs
123                 {
124                         get{ return  minOccurs; }
125                         set
126                         {
127                                 MinOccursString = value.ToString (CultureInfo.InvariantCulture);
128                         }
129                 }
130
131                 [XmlIgnore]
132                 public decimal MaxOccurs 
133                 {
134                         get{ return  maxOccurs; } 
135                         set
136                         {
137                                 if (value == decimal.MaxValue)
138                                         MaxOccursString = "unbounded";
139                                 else
140                                         MaxOccursString = value.ToString (CultureInfo.InvariantCulture);
141                         }
142                 }
143
144                 internal decimal ValidatedMinOccurs
145                 {
146                         get { return validatedMinOccurs; }
147                 }
148
149                 internal decimal ValidatedMaxOccurs
150                 {
151                         get { return validatedMaxOccurs; }
152 //                      set { validatedMaxOccurs = value; }
153                 }
154                 #endregion
155
156                 internal XmlSchemaParticle OptimizedParticle;
157
158                 internal virtual XmlSchemaParticle GetOptimizedParticle (bool isTop)
159                 {
160                         return null;
161                 }
162
163                 internal XmlSchemaParticle GetShallowClone ()
164                 {
165                         return (XmlSchemaParticle) MemberwiseClone ();
166                 }
167
168                 internal void CompileOccurence (ValidationEventHandler h, XmlSchema schema)
169                 {
170                         if (MinOccurs > MaxOccurs && !(MaxOccurs == 0 && MinOccursString == null))
171                                 error(h,"minOccurs must be less than or equal to maxOccurs");
172                         else {
173                                 if (MaxOccursString == "unbounded")
174                                         this.validatedMaxOccurs = decimal.MaxValue;
175                                 else
176                                         this.validatedMaxOccurs = maxOccurs;
177                                 if (this.validatedMaxOccurs == 0)
178                                         this.validatedMinOccurs = 0;
179                                 else
180                                         this.validatedMinOccurs = minOccurs;
181                         }
182                 }
183
184                 internal override void CopyInfo (XmlSchemaParticle obj)
185                 {
186                         base.CopyInfo (obj);
187                         if (MaxOccursString == "unbounded")
188                                 obj.maxOccurs = obj.validatedMaxOccurs = decimal.MaxValue;
189                         else 
190                                 obj.maxOccurs = obj.validatedMaxOccurs = this.ValidatedMaxOccurs;
191                         if (MaxOccurs == 0)
192                                 obj.minOccurs = obj.validatedMinOccurs = 0;
193                         else
194                                 obj.minOccurs = obj.validatedMinOccurs = this.ValidatedMinOccurs;
195                         if (MinOccursString != null)
196                                 obj.MinOccursString = MinOccursString;
197                         if (MaxOccursString != null)
198                                 obj.MaxOccursString = MaxOccursString;
199                 }
200
201                 internal virtual bool ValidateOccurenceRangeOK (XmlSchemaParticle other,
202                         ValidationEventHandler h, XmlSchema schema, bool raiseError)
203                 {
204                         if ((this.ValidatedMinOccurs < other.ValidatedMinOccurs) ||
205                                 (other.ValidatedMaxOccurs != decimal.MaxValue &&
206                                 this.ValidatedMaxOccurs > other.ValidatedMaxOccurs)) {
207                                 if (raiseError)
208                                         error (h, "Invalid derivation occurence range was found.");
209                                 return false;
210                         }
211                         return true;
212                 }
213
214                 internal virtual decimal GetMinEffectiveTotalRange ()
215                 {
216                         return ValidatedMinOccurs;
217                 }
218
219                 internal decimal GetMinEffectiveTotalRangeAllAndSequence ()
220                 {
221                         if (minEffectiveTotalRange >= 0)
222                                 return minEffectiveTotalRange;
223
224                         decimal product = 0; //this.ValidatedMinOccurs;
225                         XmlSchemaObjectCollection col = null;
226                         if (this is XmlSchemaAll)
227                                 col = ((XmlSchemaAll) this).Items;
228                         else
229                                 col = ((XmlSchemaSequence) this).Items;
230                         foreach (XmlSchemaParticle p in col)
231                                 product += p.GetMinEffectiveTotalRange ();
232
233                         minEffectiveTotalRange = product;
234                         return product;
235                 }
236
237                 // 3.9.6 Particle Emptiable
238                 internal virtual bool ValidateIsEmptiable ()
239                 {
240                         return this.validatedMinOccurs == 0 || this.GetMinEffectiveTotalRange () == 0;
241                 }
242
243                 internal virtual bool ValidateDerivationByRestriction (XmlSchemaParticle baseParticle,
244                         ValidationEventHandler h, XmlSchema schema, bool raiseError)
245                 {
246                         return false;
247                 }
248
249                 internal virtual void ValidateUniqueParticleAttribution (
250                         XmlSchemaObjectTable qnames, ArrayList nsNames,
251                         ValidationEventHandler h, XmlSchema schema)
252                 {
253                 }
254
255                 internal virtual void ValidateUniqueTypeAttribution (XmlSchemaObjectTable labels,
256                         ValidationEventHandler h, XmlSchema schema)
257                 {
258                 }
259
260                 // See http://www.thaiopensource.com/relaxng/simplify.html
261                 internal virtual void CheckRecursion (int depth, ValidationEventHandler h, XmlSchema schema)
262                 {
263                 }
264
265                 internal virtual bool ParticleEquals (XmlSchemaParticle other)
266                 {
267                         return false;
268                 }
269
270                 #region Internal Class
271                 internal class EmptyParticle : XmlSchemaParticle
272                 {
273                         internal EmptyParticle ()
274                         {
275                         }
276
277                         internal override XmlSchemaParticle GetOptimizedParticle (bool isTop)
278                         {
279                                 return this;
280                         }
281
282                         internal override bool ParticleEquals (XmlSchemaParticle other)
283                         {
284                                 return other == this || other == XmlSchemaParticle.Empty;
285                         }
286
287                         internal override bool ValidateDerivationByRestriction (XmlSchemaParticle baseParticle,
288                                 ValidationEventHandler h, XmlSchema schema, bool raiseError)
289                         {
290                                 return true;
291                         }
292
293                         internal override void CheckRecursion (int depth, 
294                                 ValidationEventHandler h, XmlSchema schema)
295                         {
296                                 // do nothing
297                         }
298
299                         internal override void ValidateUniqueParticleAttribution (XmlSchemaObjectTable qnames,
300                                 ArrayList nsNames, ValidationEventHandler h, XmlSchema schema)
301                         {
302                                 // do nothing
303                         }
304
305                         internal override void ValidateUniqueTypeAttribution (XmlSchemaObjectTable labels,
306                                 ValidationEventHandler h, XmlSchema schema)
307                         {
308                                 // do nothing
309                         }
310
311                 }
312                 #endregion
313         }
314 }