2006-08-26 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaGroupRef.cs
1 //\r
2 // System.Xml.Schema.XmlSchemaGroupBase.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;\r
32 using System.Xml.Serialization;\r
33 \r
34 namespace System.Xml.Schema\r
35 {\r
36         /// <summary>\r
37         /// Summary description for XmlSchemaGroupRef.\r
38         /// </summary>\r
39         public class XmlSchemaGroupRef : XmlSchemaParticle\r
40         {\r
41                 private XmlSchema schema;\r
42                 private XmlQualifiedName refName;\r
43                 const string xmlname = "group";\r
44                 private XmlSchemaGroup referencedGroup;\r
45 \r
46                 public XmlSchemaGroupRef()\r
47                 {\r
48                         refName = XmlQualifiedName.Empty;\r
49                 }\r
50 \r
51                 // Attribute\r
52                 [System.Xml.Serialization.XmlAttribute("ref")]\r
53                 public XmlQualifiedName RefName \r
54                 {\r
55                         get{ return  refName; } \r
56                         set{ refName = value; }\r
57                 }\r
58 \r
59                 // Post Compilation Schema Information\r
60                 [XmlIgnore]\r
61                 public XmlSchemaGroupBase Particle \r
62                 {\r
63                         get{\r
64                                 if (TargetGroup != null)\r
65                                         return TargetGroup.Particle;\r
66                                 else\r
67                                         return null;\r
68                         }\r
69                 }\r
70 \r
71                 internal XmlSchemaGroup TargetGroup\r
72                 {\r
73                         get {\r
74                                 if (referencedGroup != null && referencedGroup.IsCircularDefinition)\r
75                                         return null;\r
76                                 else\r
77                                         return referencedGroup;\r
78                         }\r
79                 }\r
80 \r
81                 /// <remarks>\r
82                 /// 1. RefName must be present\r
83                 /// </remarks>\r
84                 internal override int Compile(ValidationEventHandler h, XmlSchema schema)\r
85                 {\r
86                         // If this is already compiled this time, simply skip.\r
87                         if (CompilationId == schema.CompilationId)\r
88                                 return 0;\r
89                         this.schema = schema;\r
90 \r
91                         XmlSchemaUtil.CompileID(Id,this,schema.IDCollection,h);\r
92                         CompileOccurence (h, schema);\r
93 \r
94                         if(refName == null || refName.IsEmpty)\r
95                         {\r
96                                 error(h,"ref must be present");\r
97                         }\r
98                         else if(!XmlSchemaUtil.CheckQName(RefName))\r
99                                 error(h, "RefName must be a valid XmlQualifiedName");\r
100 \r
101                         this.CompilationId = schema.CompilationId;\r
102                         return errorCount;\r
103                 }\r
104                 \r
105                 internal override int Validate(ValidationEventHandler h, XmlSchema schema)\r
106                 {\r
107                         if (IsValidated (schema.ValidationId))\r
108                                 return errorCount;\r
109 \r
110                         referencedGroup = schema.Groups [RefName] as XmlSchemaGroup;\r
111                         // it might be missing sub components.\r
112                         if (referencedGroup == null) {\r
113                                 if (!schema.IsNamespaceAbsent (RefName.Namespace))\r
114                                         error (h, "Referenced group " + RefName + " was not found in the corresponding schema.");\r
115                         }\r
116                         // See Errata E1-26: minOccurs=0 is now allowed.\r
117                         else if (referencedGroup.Particle is XmlSchemaAll && ValidatedMaxOccurs != 1)\r
118                                 error (h, "Group reference to -all- particle must have schema component {maxOccurs}=1.");\r
119                         if (TargetGroup != null)\r
120                                 TargetGroup.Validate (h, schema);\r
121 \r
122                         ValidationId = schema.ValidationId;\r
123                         return errorCount;\r
124                 }\r
125 \r
126                 bool busy; // only for avoiding infinite loop on illegal recursion cases.\r
127                 internal override XmlSchemaParticle GetOptimizedParticle (bool isTop)\r
128                 {\r
129                         if (busy)\r
130                                 return XmlSchemaParticle.Empty;\r
131                         if (OptimizedParticle != null)\r
132                                 return OptimizedParticle;\r
133                         busy = true;\r
134                         XmlSchemaGroup g = referencedGroup != null ? referencedGroup : schema.Groups [RefName] as XmlSchemaGroup;\r
135                         if (g != null && g.Particle != null) {\r
136                                 OptimizedParticle = g.Particle;\r
137                                         OptimizedParticle = OptimizedParticle.GetOptimizedParticle (isTop);\r
138                                 if (OptimizedParticle != XmlSchemaParticle.Empty && (ValidatedMinOccurs != 1 || ValidatedMaxOccurs != 1)) {\r
139                                         OptimizedParticle = OptimizedParticle.GetShallowClone ();\r
140                                         OptimizedParticle.MinOccurs = this.MinOccurs;\r
141                                         OptimizedParticle.MaxOccurs = this.MaxOccurs;\r
142                                         OptimizedParticle.CompileOccurence (null, null);\r
143                                 }\r
144                         }\r
145                         else\r
146                                 OptimizedParticle = XmlSchemaParticle.Empty;\r
147                         busy = false;\r
148                         return OptimizedParticle;\r
149                 }\r
150 \r
151 \r
152                 internal override bool ParticleEquals (XmlSchemaParticle other)\r
153                 {\r
154                         return this.GetOptimizedParticle (true).ParticleEquals (other);\r
155                 }\r
156 \r
157                 internal override bool ValidateDerivationByRestriction (XmlSchemaParticle baseParticle,\r
158                         ValidationEventHandler h, XmlSchema schema, bool raiseError)\r
159                 {\r
160                         if (TargetGroup != null)\r
161                                 return TargetGroup.Particle.ValidateDerivationByRestriction (baseParticle, h, schema, raiseError);\r
162                         else\r
163                                 return false; // should not occur\r
164                 }\r
165 \r
166 \r
167                 internal override void CheckRecursion (int depth, ValidationEventHandler h, XmlSchema schema)\r
168                 {\r
169                         if (TargetGroup == null)\r
170                                 return;\r
171 \r
172                         if (this.recursionDepth == -1) {\r
173                                 recursionDepth = depth;\r
174                                 TargetGroup.Particle.CheckRecursion (depth, h, schema);\r
175                                 recursionDepth = -2;\r
176                         } else if (depth == recursionDepth)\r
177                                 throw new XmlSchemaException ("Circular group reference was found.", this, null);\r
178                 }\r
179 \r
180                 internal override void ValidateUniqueParticleAttribution (XmlSchemaObjectTable qnames, ArrayList nsNames,\r
181                         ValidationEventHandler h, XmlSchema schema)\r
182                 {\r
183                         if (TargetGroup != null)\r
184                                 TargetGroup.Particle.ValidateUniqueParticleAttribution (qnames, nsNames, h, schema);\r
185                 }\r
186 \r
187                 internal override void ValidateUniqueTypeAttribution (XmlSchemaObjectTable labels,\r
188                         ValidationEventHandler h, XmlSchema schema)\r
189                 {\r
190                         if (TargetGroup != null)\r
191                                 TargetGroup.Particle.ValidateUniqueTypeAttribution (labels, h, schema);\r
192                 }\r
193 \r
194 \r
195                 #region Read\r
196                 //      <group \r
197                 //               id = ID \r
198                 //               ref = QName\r
199                 //               minOccurs = ? : 1\r
200                 //               maxOccurs = ? : 1>\r
201                 //               Content: (annotation?)\r
202                 //      </group>\r
203                 internal static XmlSchemaGroupRef Read(XmlSchemaReader reader, ValidationEventHandler h)\r
204                 {\r
205                         XmlSchemaGroupRef groupref = new XmlSchemaGroupRef();\r
206                         reader.MoveToElement();\r
207 \r
208                         if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname)\r
209                         {\r
210                                 error(h,"Should not happen :1: XmlSchemaGroup.Read, name="+reader.Name,null);\r
211                                 reader.Skip();\r
212                                 return null;\r
213                         }\r
214 \r
215                         groupref.LineNumber = reader.LineNumber;\r
216                         groupref.LinePosition = reader.LinePosition;\r
217                         groupref.SourceUri = reader.BaseURI;\r
218 \r
219                         while(reader.MoveToNextAttribute())\r
220                         {\r
221                                 if(reader.Name == "id")\r
222                                 {\r
223                                         groupref.Id = reader.Value;\r
224                                 }\r
225                                 else if(reader.Name == "ref")\r
226                                 {\r
227                                         Exception innerex;\r
228                                         groupref.refName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex);\r
229                                         if(innerex != null)\r
230                                                 error(h, reader.Value + " is not a valid value for ref attribute",innerex);\r
231                                 }\r
232                                 else if(reader.Name == "maxOccurs")\r
233                                 {\r
234                                         try\r
235                                         {\r
236                                                 groupref.MaxOccursString = reader.Value;\r
237                                         }\r
238                                         catch(Exception e)\r
239                                         {\r
240                                                 error(h,reader.Value + " is an invalid value for maxOccurs",e);\r
241                                         }\r
242                                 }\r
243                                 else if(reader.Name == "minOccurs")\r
244                                 {\r
245                                         try\r
246                                         {\r
247                                                 groupref.MinOccursString = reader.Value;\r
248                                         }\r
249                                         catch(Exception e)\r
250                                         {\r
251                                                 error(h,reader.Value + " is an invalid value for minOccurs", e);\r
252                                         }\r
253                                 }\r
254                                 else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)\r
255                                 {\r
256                                         error(h,reader.Name + " is not a valid attribute for group",null);\r
257                                 }\r
258                                 else\r
259                                 {\r
260                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,groupref);\r
261                                 }\r
262                         }\r
263                         \r
264                         reader.MoveToElement();\r
265                         if(reader.IsEmptyElement)\r
266                                 return groupref;\r
267 \r
268                         //  Content: (annotation?)\r
269                         int level = 1;\r
270                         while(reader.ReadNextElement())\r
271                         {\r
272                                 if(reader.NodeType == XmlNodeType.EndElement)\r
273                                 {\r
274                                         if(reader.LocalName != xmlname)\r
275                                                 error(h,"Should not happen :2: XmlSchemaGroupRef.Read, name="+reader.Name,null);\r
276                                         break;\r
277                                 }\r
278                                 if(level <= 1 && reader.LocalName == "annotation")\r
279                                 {\r
280                                         level = 2;      //Only one annotation\r
281                                         XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);\r
282                                         if(annotation != null)\r
283                                                 groupref.Annotation = annotation;\r
284                                         continue;\r
285                                 }\r
286                                 reader.RaiseInvalidElementError();\r
287                         }                       \r
288                         return groupref;\r
289                 }\r
290                 #endregion\r
291         }\r
292 }\r