2003-10-01 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaAttribute.cs
1 //\r
2 // System.Xml.Schema.XmlSchemaAttribute.cs\r
3 //\r
4 // Authors:\r
5 //      Dwivedi, Ajay kumar  Adwiv@Yahoo.com\r
6 //      Enomoto, Atsushi     ginga@kit.hi-ho.ne.jp\r
7 //\r
8 using System;\r
9 using System.Xml;\r
10 using System.ComponentModel;\r
11 using System.Xml.Serialization;\r
12 \r
13 namespace System.Xml.Schema\r
14 {\r
15         /// <summary>\r
16         /// Summary description for XmlSchemaAttribute.\r
17         /// </summary>\r
18         public class XmlSchemaAttribute : XmlSchemaAnnotated\r
19         {\r
20                 private object attributeType;\r
21                 private string defaultValue;\r
22                 private string fixedValue;\r
23                 private string validatedDefaultValue;\r
24                 private string validatedFixedValue;\r
25                 private XmlSchemaForm form;\r
26                 private string name;\r
27                 private string targetNamespace;\r
28                 private XmlQualifiedName qualifiedName;\r
29                 private XmlQualifiedName refName;\r
30                 private XmlSchemaSimpleType schemaType;\r
31                 private XmlQualifiedName schemaTypeName;\r
32                 private XmlSchemaUse use;\r
33                 //Compilation fields\r
34                 internal bool ParentIsSchema = false;\r
35                 private XmlSchemaAttribute referencedAttribute;\r
36                 private static string xmlname = "attribute";\r
37 \r
38                 public XmlSchemaAttribute()\r
39                 {\r
40                         //FIXME: Docs says the default is optional.\r
41                         //Whereas the MS implementation has default None.\r
42                         form    = XmlSchemaForm.None;\r
43                         use             = XmlSchemaUse.None;\r
44                         schemaTypeName  = XmlQualifiedName.Empty;\r
45                         qualifiedName   = XmlQualifiedName.Empty;\r
46                         refName                 = XmlQualifiedName.Empty;\r
47                 }\r
48 \r
49                 // Properties\r
50                 #region Properties\r
51 \r
52                 [DefaultValue(null)]\r
53                 [System.Xml.Serialization.XmlAttribute("default")]\r
54                 public string DefaultValue \r
55                 {\r
56                         get{ return defaultValue;}\r
57                         set\r
58                         { // Default Value and fixed Value are mutually exclusive\r
59                                 fixedValue = null;\r
60                                 defaultValue = value;\r
61                         }\r
62                 }\r
63 \r
64                 [DefaultValue(null)]\r
65                 [System.Xml.Serialization.XmlAttribute("fixed")]\r
66                 public string FixedValue \r
67                 {\r
68                         get{ return fixedValue;}\r
69                         set\r
70                         { // Default Value and fixed Value are mutually exclusive\r
71                                 defaultValue = null;\r
72                                 fixedValue = value;\r
73                         }\r
74                 }\r
75 \r
76                 [DefaultValue(XmlSchemaForm.None)]\r
77                 [System.Xml.Serialization.XmlAttribute("form")]\r
78                 public XmlSchemaForm Form \r
79                 {\r
80                         get{ return form;}\r
81                         set{ form = value;}\r
82                 }\r
83 \r
84                 [System.Xml.Serialization.XmlAttribute("name")]\r
85                 public string Name \r
86                 {\r
87                         get{ return name;}\r
88                         set\r
89                         {\r
90                                 name  = value;\r
91                         }\r
92                 }\r
93 \r
94                 [System.Xml.Serialization.XmlAttribute("ref")]\r
95                 public XmlQualifiedName RefName \r
96                 {\r
97                         get{ return refName;}\r
98                         set\r
99                         {\r
100                                 refName = value; \r
101                         }\r
102                 }\r
103                 \r
104                 [System.Xml.Serialization.XmlAttribute("type")]\r
105                 public XmlQualifiedName SchemaTypeName \r
106                 {\r
107                         get{ return schemaTypeName;}\r
108                         set{ schemaTypeName = value;}\r
109                 }\r
110 \r
111                 [XmlElement("simpleType",Namespace=XmlSchema.Namespace)]\r
112                 public XmlSchemaSimpleType SchemaType \r
113                 {\r
114                         get{ return schemaType;}\r
115                         set{ schemaType = value;}\r
116                 }\r
117 \r
118                 [DefaultValue(XmlSchemaUse.None)]\r
119                 [System.Xml.Serialization.XmlAttribute("use")]\r
120                 public XmlSchemaUse Use \r
121                 {\r
122                         get{ return use;}\r
123                         set{ use = value;}\r
124                 }\r
125 \r
126                 [XmlIgnore]\r
127                 public XmlQualifiedName QualifiedName \r
128                 {\r
129                         get{ return qualifiedName;}\r
130                 }\r
131 \r
132                 [XmlIgnore]\r
133                 public object AttributeType \r
134                 {\r
135                         get{\r
136                                 if (referencedAttribute != null)\r
137                                         return referencedAttribute.AttributeType;\r
138                                 else\r
139                                         return attributeType;\r
140                         }\r
141                 }\r
142 \r
143                 // Post compilation default value (normalized)\r
144                 internal string ValidatedDefaultValue\r
145                 {\r
146                         // DefaultValue can be overriden in case of ref.\r
147                         get { return validatedDefaultValue; }\r
148                 }\r
149 \r
150                 // Post compilation fixed value (normalized)\r
151                 internal string ValidatedFixedValue \r
152                 {\r
153                         // FixedValue can be overriden in case of ref.\r
154                         get { return validatedFixedValue; }\r
155                 }\r
156 \r
157                 #endregion\r
158 \r
159                 /// <remarks>\r
160                 /// For an attribute:\r
161                 ///  a) If the parent is schema \r
162                 ///             1-5             are from <xs:complexType name="topLevelAttribute"> in the Schema for Schema\r
163                 ///             6-8             are from  "Constraints on XML Representations of Attribute Declarations"\r
164                 ///             9-10    are from "Attribute Declaration Schema Component"\r
165                 ///             11-16   are from "Constraints on Attribute Declaration Schema Components"\r
166                 ///             1. ref  must be absent\r
167                 ///             2. form must be absent\r
168                 ///             3. use  must be absent\r
169                 ///             4. name must be present and of type NCName\r
170                 ///             5. *NO CHECK REQUIRED* Only simple types and annotation are allowed as content\r
171                 ///             6. default and fixed must not both be present. \r
172                 ///             7. *NO CHECK REQUIRED* If default and use are both present... (Not possible since use is absent)\r
173                 ///             8. type and <simpleType> must not both be present.\r
174                 ///             9. Target Namespace should be schema's targetnamespace or absent\r
175                 ///             10. Type Definiton coressponds to <simpletype> element, or type value, or absent\r
176                 ///             11. *TO UNDERSTAND* Missing Sub-components\r
177                 ///             12. value constraint must be of the same datatype as of type\r
178                 ///             13. if the type definition is ID then there should be no value constraint.\r
179                 ///             14. name must not be xmlns\r
180                 ///             15. Targetnamespace must not be xsi. This implies the target namespace of schema can't be xsi if toplevel attributes are used.\r
181                 ///             16. *Exception to rule 15* inbuilt attributes: xsi:nil, xsi:type, xsi:schemaLocation, xsi: noNamespaceSchemaLocation\r
182                 ///     b) If the parent is complextype and ref is not set\r
183                 ///             1. name must be present and of type NCName.\r
184                 ///             2. type and <simpleType> must not both be present.\r
185                 ///             3. default and fixed must not both be present. \r
186                 ///     4. If default and use are both present, use must have the Â·actual value· optional.\r
187                 ///             5. name must not be xmlns\r
188                 ///             6. Targetnamespace must not be xsi.\r
189                 ///             7. *Exception to rule 15* inbuilt attributes: xsi:nil, xsi:type, xsi:schemaLocation, xsi: noNamespaceSchemaLocation\r
190                 ///             8. If form has actual value qualified or the schema's formdefault is qualified, targetnamespace\r
191                 ///                is same as schema's target namespace, otherwise absent.\r
192                 ///     c) if the parent is not schema and ref is set\r
193                 ///             1. name must not be present\r
194                 ///             2. all of <simpleType>, form and type must be absent. \r
195                 ///             3. default and fixed must not both be present. \r
196                 ///     4. If default and use are both present, use must have the Â·actual value· optional.\r
197                 /// </remarks>\r
198                 [MonoTODO]\r
199                 internal override int Compile(ValidationEventHandler h, XmlSchema schema)\r
200                 {\r
201                         // If this is already compiled this time, simply skip.\r
202                         if (this.IsComplied (schema.CompilationId))\r
203                                 return 0;\r
204 \r
205                         errorCount = 0;\r
206                         \r
207                         if(ParentIsSchema || isRedefineChild)//a\r
208                         {\r
209                                 if(RefName!= null && !RefName.IsEmpty) // a.1\r
210                                         error(h,"ref must be absent in the top level <attribute>");\r
211                                 \r
212                                 if(Form != XmlSchemaForm.None)  // a.2\r
213                                         error(h,"form must be absent in the top level <attribute>");\r
214                                 \r
215                                 if(Use != XmlSchemaUse.None)            // a.3\r
216                                         error(h,"use must be absent in the top level <attribute>");\r
217 \r
218                                 targetNamespace = schema.TargetNamespace;\r
219 \r
220                                 // TODO: a.10, a.11, a.12, a.13\r
221                                 CompileCommon(h, schema, true);\r
222                         }\r
223                         else // local\r
224                         {\r
225                                 //FIXME: How to Use of AttributeFormDefault????\r
226                                 if(RefName == null || RefName.IsEmpty)\r
227                                 {\r
228                                         if(form == XmlSchemaForm.Qualified || (form == XmlSchemaForm.None && schema.AttributeFormDefault == XmlSchemaForm.Qualified))\r
229                                                 this.targetNamespace = schema.TargetNamespace;\r
230                                         else\r
231                                                 this.targetNamespace = "";\r
232 \r
233                                         //TODO: b.8\r
234                                         CompileCommon(h, schema, true);\r
235                                 }\r
236                                 else\r
237                                 {\r
238                                         if(this.name != null)\r
239                                                 error(h,"name must be absent if ref is present");\r
240                                         if(this.form != XmlSchemaForm.None)\r
241                                                 error(h,"form must be absent if ref is present");\r
242                                         if(this.schemaType != null)\r
243                                                 error(h,"simpletype must be absent if ref is present");\r
244                                         if(this.schemaTypeName != null && !this.schemaTypeName.IsEmpty)\r
245                                                 error(h,"type must be absent if ref is present");\r
246 \r
247                                         CompileCommon(h, schema, false);\r
248                                 }\r
249                         }\r
250 \r
251                         this.CompilationId = schema.CompilationId;\r
252                         return errorCount;\r
253                 }\r
254                 \r
255                 private void CompileCommon(ValidationEventHandler h, XmlSchema schema, bool refIsNotPresent)\r
256                 {\r
257                         if(refIsNotPresent)\r
258                         {\r
259                                 if(Name == null)        //a.4, b.1, \r
260                                         error(h,"Required attribute name must be present");\r
261                                 else if(!XmlSchemaUtil.CheckNCName(Name)) // a.4.2, b1.2\r
262                                         error(h,"attribute name must be NCName");\r
263                                 else if(Name == "xmlns") // a.14 , b5\r
264                                         error(h,"attribute name must not be xmlns");\r
265                                 else\r
266                                         qualifiedName = new XmlQualifiedName(Name, targetNamespace);\r
267 \r
268                                 if(SchemaType != null)\r
269                                 {\r
270                                         if(SchemaTypeName != null && !SchemaTypeName.IsEmpty) // a.8\r
271                                                 error(h,"attribute can't have both a type and <simpleType> content");\r
272 \r
273                                         errorCount += SchemaType.Compile(h, schema); \r
274                                 }\r
275 \r
276                                 if(SchemaTypeName != null && !XmlSchemaUtil.CheckQName(SchemaTypeName))\r
277                                         error(h,SchemaTypeName+" is not a valid QName");\r
278                         }\r
279                         else\r
280                         {\r
281                                 if(RefName == null || RefName.IsEmpty) \r
282                                         throw new NotImplementedException ("Error: Should Never Happen. refname must be present");\r
283                                 else\r
284                                         qualifiedName = RefName;\r
285                         }\r
286 \r
287                         if(schema.TargetNamespace == XmlSchema.InstanceNamespace && Name != "nil" && Name != "type" \r
288                                 && Name != "schemaLocation" && Name != "noNamespaceSchemaLocation") // a.15, a.16\r
289                                 error(h,"targetNamespace can't be " + XmlSchema.InstanceNamespace);\r
290 \r
291                         if(DefaultValue != null && FixedValue != null) // a.6, b.3, c.3\r
292                                 error(h,"default and fixed must not both be present in an Attribute");\r
293 \r
294                         if(DefaultValue != null && Use != XmlSchemaUse.None && Use != XmlSchemaUse.Optional)\r
295                                 error(h,"if default is present, use must be optional");\r
296 \r
297                         XmlSchemaUtil.CompileID(Id, this, schema.IDCollection, h);\r
298                 }\r
299 \r
300                 /// <summary>\r
301                 /// Schema Component: \r
302                 ///                     QName, SimpleType, Scope, Default|Fixed, annotation\r
303                 /// </summary>\r
304                 [MonoTODO]\r
305                 internal override int Validate(ValidationEventHandler h, XmlSchema schema)\r
306                 {\r
307                         if(IsValidated (schema.ValidationId))\r
308                                 return errorCount;\r
309 \r
310                         // -- Attribute Declaration Schema Component --\r
311                         // {name}, {target namespace} -> QualifiedName. Already Compile()d.\r
312                         // {type definition} -> attributeType. From SchemaType or SchemaTypeName.\r
313                         // {scope} -> ParentIsSchema | isRedefineChild.\r
314                         // {value constraint} -> ValidatedFixedValue, ValidatedDefaultValue.\r
315                         // {annotation}\r
316                         // -- Attribute Use Schema Component --\r
317                         // {required}\r
318                         // {attribute declaration}\r
319                         // {value constraint}\r
320 \r
321                         // First, fill type information for type reference\r
322                         if (SchemaTypeName != null && SchemaTypeName != XmlQualifiedName.Empty)\r
323                         {\r
324                                 // If type is null, then it is missing sub components .\r
325                                 XmlSchemaType type = schema.SchemaTypes [SchemaTypeName] as XmlSchemaType;\r
326                                 if (type is XmlSchemaComplexType)\r
327                                         error(h,"An attribute can't have complexType Content");\r
328                                 else if (type != null) {        // simple type\r
329                                         errorCount += type.Validate (h, schema);\r
330                                         attributeType = type;\r
331                                 }\r
332                                 else if (SchemaTypeName == XmlSchemaComplexType.AnyTypeName)\r
333                                         attributeType = XmlSchemaComplexType.AnyType;
334                                 else if (SchemaTypeName.Namespace == XmlSchema.Namespace) {\r
335                                         attributeType = XmlSchemaDatatype.FromName (SchemaTypeName);\r
336                                         if (attributeType == null)\r
337                                                 error (h, "Invalid xml schema namespace datatype was specified.");\r
338                                 }\r
339                                 // otherwise, it might be missing sub components.\r
340                                 else if (!schema.IsNamespaceAbsent (SchemaTypeName.Namespace))\r
341                                         error (h, "Referenced schema type " + SchemaTypeName + " was not found in the corresponding schema.");\r
342                         }\r
343 \r
344                         // Then, fill type information for the type references for the referencing attributes\r
345                         if (RefName != null && RefName != XmlQualifiedName.Empty)\r
346                         {\r
347                                 referencedAttribute = schema.Attributes [RefName] as XmlSchemaAttribute;\r
348                                 // If el is null, then it is missing sub components .\r
349                                 if (referencedAttribute != null)\r
350                                         errorCount += referencedAttribute.Validate (h, schema);\r
351                                 // otherwise, it might be missing sub components.\r
352                                 else if (!schema.IsNamespaceAbsent (RefName.Namespace))\r
353                                         error (h, "Referenced attribute " + RefName + " was not found in the corresponding schema.");\r
354                         }\r
355 \r
356                         if (attributeType == null)\r
357                                 attributeType = XmlSchemaSimpleType.AnySimpleType;\r
358 \r
359                         // Validate {value constraints}\r
360                         if (defaultValue != null || fixedValue != null) {\r
361                                 XmlSchemaDatatype datatype = attributeType as XmlSchemaDatatype;\r
362                                 if (datatype == null)\r
363                                         datatype = ((XmlSchemaSimpleType) attributeType).Datatype;\r
364                                 if (datatype.TokenizedType == XmlTokenizedType.QName)\r
365                                         error (h, "By the defection of the W3C XML Schema specification, it is impossible to supply QName default or fixed values.");\r
366                                 else {\r
367                                         try {\r
368                                                 if (defaultValue != null) {\r
369                                                         validatedDefaultValue = datatype.Normalize (defaultValue);\r
370                                                         datatype.ParseValue (validatedDefaultValue, null, null);\r
371                                                 }\r
372                                         } catch (Exception ex) {\r
373                                                 // FIXME: This is not a good way to handle exception.\r
374                                                 error (h, "The Attribute's default value is invalid with its type definition.", ex);\r
375                                         }\r
376                                         try {\r
377                                                 if (fixedValue != null) {\r
378                                                         validatedFixedValue = datatype.Normalize (fixedValue);\r
379                                                         datatype.ParseValue (validatedFixedValue, null, null);\r
380                                                 }\r
381                                         } catch (Exception ex) {\r
382                                                 // FIXME: This is not a good way to handle exception.\r
383                                                 error (h, "The Attribute's fixed value is invalid with its type definition.", ex);\r
384                                         }\r
385                                 }\r
386                         }\r
387 \r
388                         ValidationId = schema.ValidationId;\r
389                         return errorCount;\r
390                 }\r
391 \r
392                 //<attribute\r
393                 //  default = string\r
394                 //  fixed = string\r
395                 //  form = (qualified | unqualified)\r
396                 //  id = ID\r
397                 //  name = NCName\r
398                 //  ref = QName\r
399                 //  type = QName\r
400                 //  use = (optional | prohibited | required) : optional\r
401                 //  {any attributes with non-schema namespace . . .}>\r
402                 //  Content: (annotation?, (simpleType?))\r
403                 //</attribute>\r
404                 internal static XmlSchemaAttribute Read(XmlSchemaReader reader, ValidationEventHandler h)\r
405                 {\r
406                         XmlSchemaAttribute attribute = new XmlSchemaAttribute();\r
407                         reader.MoveToElement();\r
408 \r
409                         if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname)\r
410                         {\r
411                                 error(h,"Should not happen :1: XmlSchemaAttribute.Read, name="+reader.Name,null);\r
412                                 reader.SkipToEnd();\r
413                                 return null;\r
414                         }\r
415 \r
416                         attribute.LineNumber = reader.LineNumber;\r
417                         attribute.LinePosition = reader.LinePosition;\r
418                         attribute.SourceUri = reader.BaseURI;\r
419 \r
420                         while(reader.MoveToNextAttribute())\r
421                         {\r
422                                 if(reader.Name == "default")\r
423                                 {\r
424                                         attribute.defaultValue = reader.Value;\r
425                                 }\r
426                                 else if(reader.Name == "fixed")\r
427                                 {\r
428                                         attribute.fixedValue = reader.Value;\r
429                                 }\r
430                                 else if(reader.Name == "form")\r
431                                 {\r
432                                         Exception innerex;\r
433                                         attribute.form = XmlSchemaUtil.ReadFormAttribute(reader,out innerex);\r
434                                         if(innerex != null)\r
435                                                 error(h, reader.Value + " is not a valid value for form attribute", innerex);\r
436                                 }\r
437                                 else if(reader.Name == "id")\r
438                                 {\r
439                                         attribute.Id = reader.Value;\r
440                                 }\r
441                                 else if(reader.Name == "name")\r
442                                 {\r
443                                         attribute.name = reader.Value;\r
444                                 }\r
445                                 else if(reader.Name == "ref")\r
446                                 {\r
447                                         Exception innerex;\r
448                                         attribute.refName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex);\r
449                                         if(innerex != null)\r
450                                                 error(h, reader.Value + " is not a valid value for ref attribute",innerex);\r
451                                 }\r
452                                 else if(reader.Name == "type")\r
453                                 {\r
454                                         Exception innerex;\r
455                                         attribute.schemaTypeName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex);\r
456                                         if(innerex != null)\r
457                                                 error(h, reader.Value + " is not a valid value for type attribute",innerex);\r
458                                 }\r
459                                 else if(reader.Name == "use")\r
460                                 {\r
461                                         Exception innerex;\r
462                                         attribute.use = XmlSchemaUtil.ReadUseAttribute(reader,out innerex);\r
463                                         if(innerex != null)\r
464                                                 error(h, reader.Value + " is not a valid value for use attribute", innerex);\r
465                                 }\r
466                                 else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)\r
467                                 {\r
468                                         error(h,reader.Name + " is not a valid attribute for attribute",null);\r
469                                 }\r
470                                 else\r
471                                 {\r
472                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,attribute);\r
473                                 }\r
474                         }\r
475                         \r
476                         reader.MoveToElement();\r
477                         if(reader.IsEmptyElement)\r
478                                 return attribute;\r
479 \r
480                         //  Content: (annotation?, (simpleType?))\r
481                         int level = 1;\r
482                         while(reader.ReadNextElement())\r
483                         {\r
484                                 if(reader.NodeType == XmlNodeType.EndElement)\r
485                                 {\r
486                                         if(reader.LocalName != xmlname)\r
487                                                 error(h,"Should not happen :2: XmlSchemaAttribute.Read, name="+reader.Name,null);\r
488                                         break;\r
489                                 }\r
490                                 if(level <= 1 && reader.LocalName == "annotation")\r
491                                 {\r
492                                         level = 2; //Only one annotation\r
493                                         XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);\r
494                                         if(annotation != null)\r
495                                                 attribute.Annotation = annotation;\r
496                                         continue;\r
497                                 }\r
498                                 if(level <=2 && reader.LocalName == "simpleType")\r
499                                 {\r
500                                         level = 3;\r
501                                         XmlSchemaSimpleType stype = XmlSchemaSimpleType.Read(reader,h);\r
502                                         if(stype != null)\r
503                                                 attribute.schemaType = stype;\r
504                                         continue;\r
505                                 }\r
506                                 reader.RaiseInvalidElementError();\r
507                         }\r
508                         return attribute;\r
509                 }\r
510                 \r
511         }\r
512 }\r