// Author: Dwivedi, Ajay kumar // Adwiv@Yahoo.com using System; using System.Xml; using System.ComponentModel; using System.Xml.Serialization; namespace System.Xml.Schema { /// /// Summary description for XmlSchemaAttribute. /// public class XmlSchemaAttribute : XmlSchemaAnnotated { private object attributeType; private string defaultValue; private string fixedValue; private XmlSchemaForm form; private string name; private XmlQualifiedName qualifiedName; private XmlQualifiedName refName; private XmlSchemaSimpleType schemaType; private XmlQualifiedName schemaTypeName; private XmlSchemaUse use; //Compilation fields internal bool parentIsSchema = false; private static string xmlname = "attribute"; public XmlSchemaAttribute() { //FIXME: Docs says the default is optional. //Whereas the MS implementation has default None. form = XmlSchemaForm.None; use = XmlSchemaUse.None; schemaTypeName = XmlQualifiedName.Empty; qualifiedName = XmlQualifiedName.Empty; refName = XmlQualifiedName.Empty; } // Properties [XmlIgnore] public object AttributeType { //FIXME: This is not correct. Is it? get{ return attributeType; } } [DefaultValue(null)] [System.Xml.Serialization.XmlAttribute("default")] public string DefaultValue { get{ return defaultValue;} set { // Default Value and fixed Value are mutually exclusive fixedValue = null; defaultValue = value; } } [DefaultValue(null)] [System.Xml.Serialization.XmlAttribute("fixed")] public string FixedValue { get{ return fixedValue;} set { // Default Value and fixed Value are mutually exclusive defaultValue = null; fixedValue = value; } } [DefaultValue(XmlSchemaForm.None)] [System.Xml.Serialization.XmlAttribute("form")] public XmlSchemaForm Form { get{ return form;} set{ form = value;} } [System.Xml.Serialization.XmlAttribute("name")] public string Name { get{ return name;} set { name = value; } } [XmlIgnore] public XmlQualifiedName QualifiedName { get{ return qualifiedName;} } [System.Xml.Serialization.XmlAttribute("ref")] public XmlQualifiedName RefName { get{ return refName;} set { refName = value; } } [XmlElement("simpleType",Namespace="http://www.w3.org/2001/XMLSchema")] public XmlSchemaSimpleType SchemaType { get{ return schemaType;} set{ schemaType = value;} } [System.Xml.Serialization.XmlAttribute("type")] public XmlQualifiedName SchemaTypeName { get{ return schemaTypeName;} set{ schemaTypeName = value;} } [DefaultValue(XmlSchemaUse.None)] [System.Xml.Serialization.XmlAttribute("use")] public XmlSchemaUse Use { get{ return use;} set{ use = value;} } /// /// For an attribute: /// a) If the parent is schema /// 1-5 are from in the Schema for Schema /// 6-8 are from "Constraints on XML Representations of Attribute Declarations" /// 9-10 are from "Attribute Declaration Schema Component" /// 11-16 are from "Constraints on Attribute Declaration Schema Components" /// 1. ref must be absent /// 2. form must be absent /// 3. use must be absent /// 4. name must be present and of type NCName /// 5. *NO CHECK REQUIRED* Only simple types and annotation are allowed as content /// 6. default and fixed must not both be present. /// 7. *NO CHECK REQUIRED* If default and use are both present... (Not possible since use is absent) /// 8. type and must not both be present. /// 9. Target Namespace should be schema's targetnamespace or absent /// 10. Type Definiton coressponds to element, or type value, or absent /// 11. *TO UNDERSTAND* Missing Sub-components /// 12. value constraint must be of the same datatype as of type /// 13. if the type definition is ID then there should be no value constraint. /// 14. name must not be xmlns /// 15. Targetnamespace must not be xsi. This implies the target namespace of schema can't be xsi if toplevel attributes are used. /// 16. *Exception to rule 15* inbuilt attributes: xsi:nil, xsi:type, xsi:schemaLocation, xsi: noNamespaceSchemaLocation /// b) If the parent is complextype and ref is not set /// 1. name must be present and of type NCName. /// 2. type and must not both be present. /// 3. default and fixed must not both be present. /// 4. If default and use are both present, use must have the ·actual value· optional. /// 5. name must not be xmlns /// 6. Targetnamespace must not be xsi. /// 7. *Exception to rule 15* inbuilt attributes: xsi:nil, xsi:type, xsi:schemaLocation, xsi: noNamespaceSchemaLocation /// 8. If form has actual value qualified or the schema's formdefault is qualified, targetnamespace /// is same as schema's target namespace, otherwise absent. /// c) if the parent is not schema and ref is set /// 1. name must not be present /// 2. all of , form and type must be absent. /// 3. default and fixed must not both be present. /// 4. If default and use are both present, use must have the ·actual value· optional. /// [MonoTODO] internal int Compile(ValidationEventHandler h, XmlSchemaInfo info) { errorCount = 0; if(parentIsSchema)//a { if(RefName!= null && !RefName.IsEmpty) // a.1 error(h,"ref must be absent in the top level "); if(Form != XmlSchemaForm.None) // a.2 error(h,"form must be absent in the top level "); if(Use != XmlSchemaUse.None) // a.3 error(h,"use must be absent in the top level "); // TODO: a.10, a.11, a.12, a.13 CompileCommon(h,info, true); } else // local { //FIXME: How to Use of AttributeFormDefault???? if(RefName == null || RefName.IsEmpty) { //TODO: b.8 CompileCommon(h,info, true); } else { if(this.name != null) error(h,"name must be absent if ref is present"); if(this.form != XmlSchemaForm.None) error(h,"form must be absent if ref is present"); if(this.schemaType != null) error(h,"simpletype must be absent if ref is present"); if(this.schemaTypeName != null && !this.schemaTypeName.IsEmpty) error(h,"type must be absent if ref is present"); CompileCommon(h,info,false); } } return errorCount; } private void CompileCommon(ValidationEventHandler h, XmlSchemaInfo info, bool refIsNotPresent) { if(refIsNotPresent) { if(Name == null) //a.4, b.1, error(h,"Required attribute name must be present"); else if(!XmlSchemaUtil.CheckNCName(Name)) // a.4.2, b1.2 error(h,"attribute name must be NCName"); else if(Name == "xmlns") // a.14 , b5 error(h,"attribute name must not be xmlns"); else qualifiedName = new XmlQualifiedName(Name, info.TargetNamespace); if(SchemaType != null) { if(SchemaTypeName != null && !SchemaTypeName.IsEmpty) // a.8 error(h,"attribute can't have both a type and content"); errorCount += SchemaType.Compile(h,info); } if(SchemaTypeName != null && !XmlSchemaUtil.CheckQName(SchemaTypeName)) error(h,SchemaTypeName+" is not a valid QName"); } else { if(RefName == null || RefName.IsEmpty) error(h,"Error: Should Never Happen. refname must be present"); else qualifiedName = RefName; } if(info.TargetNamespace == XmlSchema.InstanceNamespace && Name != "nil" && Name != "type" && Name != "schemaLocation" && Name != "noNamespaceSchemaLocation") // a.15, a.16 error(h,"targetNamespace can't be " + XmlSchema.InstanceNamespace); if(DefaultValue != null && FixedValue != null) // a.6, b.3, c.3 error(h,"default and fixed must not both be present in an Attribute"); if(DefaultValue != null && Use != XmlSchemaUse.None && Use != XmlSchemaUse.Optional) error(h,"if default is present, use must be optional"); XmlSchemaUtil.CompileID(Id, this, info.IDCollection, h); } [MonoTODO] internal int Validate(ValidationEventHandler h) { return errorCount; } // // Content: (annotation?, (simpleType?)) // internal static XmlSchemaAttribute Read(XmlSchemaReader reader, ValidationEventHandler h) { XmlSchemaAttribute attribute = new XmlSchemaAttribute(); reader.MoveToElement(); if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname) { error(h,"Should not happen :1: XmlSchemaAttribute.Read, name="+reader.Name,null); reader.SkipToEnd(); return null; } attribute.LineNumber = reader.LineNumber; attribute.LinePosition = reader.LinePosition; attribute.SourceUri = reader.BaseURI; while(reader.MoveToNextAttribute()) { if(reader.Name == "default") { attribute.defaultValue = reader.Value; } else if(reader.Name == "fixed") { attribute.fixedValue = reader.Value; } else if(reader.Name == "form") { Exception innerex; attribute.form = XmlSchemaUtil.ReadFormAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for form attribute", innerex); } else if(reader.Name == "id") { attribute.Id = reader.Value; } else if(reader.Name == "name") { attribute.name = reader.Value; } else if(reader.Name == "ref") { Exception innerex; attribute.refName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for ref attribute",innerex); } else if(reader.Name == "type") { Exception innerex; attribute.schemaTypeName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for type attribute",innerex); } else if(reader.Name == "use") { Exception innerex; attribute.use = XmlSchemaUtil.ReadUseAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for use attribute", innerex); } else if(reader.NamespaceURI == "" || reader.NamespaceURI == XmlSchema.Namespace) { error(h,reader.Name + " is not a valid attribute for attribute",null); } else { if(reader.Prefix == "xmlns") attribute.Namespaces.Add(reader.LocalName, reader.Value); else if(reader.Name == "xmlns") attribute.Namespaces.Add("",reader.Value); //TODO: Add to Unhandled attributes } } reader.MoveToElement(); if(reader.IsEmptyElement) return attribute; // Content: (annotation?, (simpleType?)) int level = 1; while(reader.ReadNextElement()) { if(reader.NodeType == XmlNodeType.EndElement) { if(reader.LocalName != xmlname) error(h,"Should not happen :2: XmlSchemaAttribute.Read, name="+reader.Name,null); break; } if(level <= 1 && reader.LocalName == "annotation") { level = 2; //Only one annotation XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h); if(annotation != null) attribute.Annotation = annotation; continue; } if(level <=2 && reader.LocalName == "simpleType") { level = 3; XmlSchemaSimpleType stype = XmlSchemaSimpleType.Read(reader,h); if(stype != null) attribute.schemaType = stype; continue; } reader.RaiseInvalidElementError(); } return attribute; } } }