// 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;
}
}
}