namespace Mono.Util {\r
class MonoXSD {\r
\r
- static BindingFlags instance_flag = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance;\r
+ static BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;\r
static XmlSchema schema = new XmlSchema ();\r
- static readonly string xs = "http://www.w3.org/2001/XMLSchema";\r
+ static readonly string xs = "http://www.w3.org/2001/XMLSchema";\r
static Hashtable generatedSchemaTypes;\r
\r
static void Main (string [] args) \r
{\r
string assembly = args [0];\r
\r
- if (assembly.EndsWith (".dll") || assembly.EndsWith (".exe")) {\r
- GenerateSchema (assembly);\r
- } else {\r
+ if (assembly.EndsWith (".dll") || assembly.EndsWith (".exe"))\r
+ try {\r
+ WriteSchema (assembly);\r
+ } catch (ArgumentException e) {\r
+ Console.WriteLine (e.Message + "\n");\r
+ Environment.Exit (0);\r
+ }\r
+ \r
+ else {\r
Console.WriteLine ("Not supported.");\r
return;\r
}\r
/// <summary>\r
/// Writes a schema for each type in the assembly\r
/// </summary>\r
- static void GenerateSchema (string assembly) \r
+ static void WriteSchema (string assembly) \r
{\r
Assembly a = Assembly.LoadFrom (assembly);\r
generatedSchemaTypes = new Hashtable ();\r
if (a == null)\r
throw new NullReferenceException ("Null assembly");\r
\r
+ XmlSchemaType schemaType;\r
+\r
foreach (Type t in a.GetTypes ()) {\r
- XmlSchemaType schemaType = GenerateSchemaType (t);\r
- XmlSchemaElement schemaElement = GenerateSchemaElement (t, schemaType);\r
+ try {\r
+ schemaType = WriteSchemaType (t);\r
+ } catch (ArgumentException e) {\r
+ throw new ArgumentException (String.Format ("Error: We cannot process {0}\n{1}", assembly, e.Message));\r
+ }\r
+\r
+ if (schemaType == null)\r
+ continue;\r
+\r
+ XmlSchemaElement schemaElement = WriteSchemaElement (t, schemaType);\r
schema.Items.Add (schemaElement);\r
schema.Items.Add (schemaType);\r
}\r
\r
+ schema.ElementFormDefault = XmlSchemaForm.Qualified;\r
schema.Compile (new ValidationEventHandler (OnSchemaValidation));\r
schema.Write (Console.Out);\r
Console.WriteLine ();\r
/// Given a Type and its associated schema type, add aa '<xs;element>' node \r
/// to the schema.\r
/// </summary>\r
- static XmlSchemaElement GenerateSchemaElement (Type type, XmlSchemaType schemaType) \r
+ static XmlSchemaElement WriteSchemaElement (Type type, XmlSchemaType schemaType) \r
{\r
XmlSchemaElement schemaElement = new XmlSchemaElement ();\r
schemaElement.Name = type.Name;\r
- \r
+\r
if (schemaType.QualifiedName == null || schemaType.QualifiedName == XmlQualifiedName.Empty)\r
schemaElement.SchemaTypeName = new XmlQualifiedName (schemaType.Name);\r
+ \r
else\r
schemaElement.SchemaTypeName = schemaType.QualifiedName;\r
- \r
+ \r
+ if (schemaType is XmlSchemaComplexType)\r
+ schemaElement.IsNillable = true;\r
+\r
return schemaElement;\r
}\r
\r
/// From a Type, create a corresponding ComplexType node to\r
/// represent this Type.\r
/// </summary>\r
- static XmlSchemaType GenerateSchemaType (Type type) \r
+ static XmlSchemaType WriteSchemaType (Type type) \r
{\r
- if (generatedSchemaTypes.Contains (type.FullName))\r
+ if (generatedSchemaTypes.Contains (type.FullName)) // Caching\r
return generatedSchemaTypes [type.FullName] as XmlSchemaType;\r
\r
- if (type != typeof (object) && type.BaseType != typeof (object)) \r
- return GenerateComplexContent (type);\r
+ XmlSchemaType schemaType = new XmlSchemaType ();\r
+\r
+ if (!type.IsAbstract && typeof (System.Delegate).IsAssignableFrom (type))\r
+ return null;\r
+\r
+ if (type.IsEnum)\r
+ schemaType = WriteEnum (type);\r
+\r
+ else if (type != typeof (object) && type.BaseType != typeof (object)) {\r
+ \r
+ try {\r
+ schemaType = WriteComplexType (type);\r
+ } catch (ArgumentException e) {\r
+ throw e;\r
+ }\r
+\r
+ } else {\r
+ XmlSchemaComplexType complexType = new XmlSchemaComplexType ();\r
+ complexType.Name = type.Name;\r
+ FieldInfo [] fields = type.GetFields (flags);\r
+ PropertyInfo [] properties = type.GetProperties (flags);\r
+ XmlSchemaSequence sequence;\r
+\r
+ try {\r
+ sequence = PopulateSequence (fields, properties);\r
+ } catch (ArgumentException e) {\r
+ throw new ArgumentException (String.Format ("There is an error in '{0}'\n\t{1}", type.Name, e.Message));\r
+ }\r
+ complexType.Particle = sequence; \r
+ generatedSchemaTypes.Add (type.FullName, complexType);\r
+\r
+ schemaType = complexType;\r
+ }\r
+\r
+ return schemaType;\r
+ }\r
+\r
+ static XmlSchemaType WriteEnum (Type type) \r
+ {\r
+ if (type.IsEnum == false)\r
+ throw new Exception (String.Format ("{0} is not an enumeration.", type.Name));\r
+\r
+ XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType ();\r
+ simpleType.Name = type.Name;\r
+ FieldInfo [] fields = type.GetFields ();\r
\r
+ XmlSchemaSimpleTypeRestriction simpleRestriction = new XmlSchemaSimpleTypeRestriction ();\r
+ simpleType.Content = simpleRestriction;\r
+ simpleRestriction.BaseTypeName = new XmlQualifiedName ("string", xs);\r
+\r
+ foreach (FieldInfo field in fields) {\r
+ if (field.IsSpecialName)\r
+ continue;\r
+\r
+ XmlSchemaEnumerationFacet e = new XmlSchemaEnumerationFacet ();\r
+ e.Value = field.Name;\r
+ simpleRestriction.Facets.Add (e);\r
+ }\r
+\r
+ generatedSchemaTypes.Add (type.FullName, simpleType);\r
+ return simpleType;\r
+ }\r
+\r
+ static XmlSchemaType WriteArray (Type type) \r
+ {\r
XmlSchemaComplexType complexType = new XmlSchemaComplexType ();\r
- complexType.Name = type.Name;\r
- FieldInfo [] fields = type.GetFields (instance_flag);\r
- XmlSchemaSequence sequence = PopulateSequence (fields);\r
+ string type_name = type.Name.Substring (0, type.Name.Length - 2);\r
+ complexType.Name = "ArrayOf" + type_name;\r
+\r
+ XmlSchemaSequence sequence = new XmlSchemaSequence ();\r
+ XmlSchemaElement element = new XmlSchemaElement ();\r
+\r
+ element.MinOccurs = 0;\r
+ element.MaxOccursString = "unbounded";\r
+ element.IsNillable = true;\r
+ element.Name = type_name.ToLower (); \r
+ element.SchemaTypeName = GetQualifiedName (\r
+ type.FullName.Substring (0, type.FullName.Length - 2));\r
+ \r
+ sequence.Items.Add (element);\r
complexType.Particle = sequence;\r
\r
generatedSchemaTypes.Add (type.FullName, complexType);\r
- \r
- return complexType;\r
+ return complexType; \r
}\r
\r
+\r
/// <summary>\r
- /// Handle schema derivation by extension.\r
+ /// Handle derivation by extension. \r
+ /// If type is null, it'll create a new complexType \r
+ /// with an XmlAny node in its sequence child node.\r
/// </summary>\r
- static XmlSchemaType GenerateComplexContent (Type type) \r
+ static XmlSchemaType WriteComplexType (Type type) \r
{\r
- XmlSchemaType baseSchemaType = GenerateSchemaType (type.BaseType);\r
+ //\r
+ // Recursively generate schema for all parent types\r
+ //\r
+ if (type != null && type.BaseType == typeof (object))\r
+ return WriteSchemaType (type);\r
\r
XmlSchemaComplexType complexType = new XmlSchemaComplexType ();\r
- complexType.Name = type.Name;\r
-\r
- FieldInfo [] fields = type.GetFields (instance_flag);\r
+ XmlSchemaSequence sequence;\r
\r
- XmlSchemaComplexContent content = new XmlSchemaComplexContent ();\r
+ if (type == null) {\r
+ complexType.IsMixed = true;\r
+ sequence = new XmlSchemaSequence ();\r
+ sequence.Items.Add (new XmlSchemaAny ());\r
+ complexType.Particle = sequence;\r
+ return complexType;\r
+ }\r
XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension ();\r
- XmlSchemaSequence sequence = PopulateSequence (fields);\r
+ XmlSchemaComplexContent content = new XmlSchemaComplexContent ();\r
+ \r
+ complexType.ContentModel = content;\r
+ content.Content = extension;\r
+\r
+ XmlSchemaType baseSchemaType = WriteSchemaType (type.BaseType);\r
+\r
+ complexType.Name = type.Name;\r
+\r
+ FieldInfo [] fields = type.GetFields (flags);\r
+ PropertyInfo [] properties = type.GetProperties (flags);\r
\r
- extension.Particle = sequence;\r
+ try {\r
+ sequence = PopulateSequence (fields, properties);\r
+ } catch (ArgumentException e) {\r
+ throw new ArgumentException (String.Format ("There is an error in '{0}'\n\t{1}", type.Name, e.Message));\r
+ }\r
+ \r
extension.BaseTypeName = new XmlQualifiedName (baseSchemaType.Name);\r
- content.Content = extension;\r
- complexType.ContentModel = content;\r
+ extension.Particle = sequence;\r
\r
- return complexType;\r
+ generatedSchemaTypes.Add (type.FullName, complexType);\r
+ return complexType;\r
} \r
\r
- static XmlSchemaSequence PopulateSequence (FieldInfo [] fields) \r
+ static XmlSchemaSequence PopulateSequence (FieldInfo [] fields, PropertyInfo [] properties) \r
{\r
+ if (fields == null && properties == null)\r
+ return null;\r
+\r
XmlSchemaSequence sequence = new XmlSchemaSequence ();\r
+ \r
+ try {\r
+ foreach (FieldInfo field in fields)\r
+ AddElement (sequence, field, field.FieldType);\r
\r
- foreach (FieldInfo field in fields) {\r
- XmlSchemaElement fieldElement = new XmlSchemaElement ();\r
- fieldElement.Name = field.Name;\r
- fieldElement.SchemaTypeName = GetSchemaTypeQName (field);\r
- sequence.Items.Add (fieldElement);\r
+ } catch (Exception e) {\r
+ throw e;\r
}\r
\r
+ if (properties == null)\r
+ return sequence;\r
+\r
+ try {\r
+ foreach (PropertyInfo property in properties)\r
+ AddElement (sequence, property, property.PropertyType);\r
+\r
+ } catch (ArgumentException e) {\r
+ throw e;\r
+ }\r
+ \r
return sequence;\r
}\r
\r
- ///<summary>\r
- /// Populates element nodes inside a '<xs:sequence>' node.\r
- ///</summary>\r
- static XmlQualifiedName GetSchemaTypeQName (FieldInfo field) \r
+ static void AddElement (XmlSchemaSequence sequence, MemberInfo member, Type type) \r
+ {\r
+ //\r
+ // Only read/write properties are supported.\r
+ //\r
+ if (member is PropertyInfo) {\r
+ PropertyInfo p = (PropertyInfo) member;\r
+ if (! (p.CanRead && p.CanWrite))\r
+ return;\r
+ }\r
+\r
+ //\r
+ // readonly fields are not supported.\r
+ //\r
+ if (member is FieldInfo) {\r
+ FieldInfo f = (FieldInfo) member;\r
+ if (f.IsInitOnly || f.IsLiteral )\r
+ return;\r
+ }\r
+\r
+ //\r
+ // delegates are not supported.\r
+ //\r
+ if (!type.IsAbstract && typeof (System.Delegate).IsAssignableFrom (type))\r
+ return;\r
+\r
+ if (type.IsArray) {\r
+ XmlSchemaType arrayType = WriteArray (type);\r
+ schema.Items.Add (arrayType);\r
+ }\r
+\r
+ XmlSchemaElement element = new XmlSchemaElement ();\r
+ element.Name = member.Name;\r
+\r
+ XmlQualifiedName qname = GetQualifiedName (type);\r
+\r
+ if (qname == null)\r
+ throw new ArgumentException (String.Format ("The type '{0}' cannot be represented in XML Schema.", type.FullName));\r
+\r
+ if (qname != XmlQualifiedName.Empty)\r
+ element.SchemaTypeName = qname;\r
+\r
+ if (qname.Name == "xml") {\r
+ element.SchemaType = WriteComplexType (null);\r
+ element.SchemaTypeName = XmlQualifiedName.Empty; // 'xml' is just a temporary name\r
+ }\r
+\r
+ if (type.IsClass)\r
+ element.MinOccurs = 0;\r
+ else\r
+ element.MinOccurs = 1;\r
+ element.MaxOccurs = 1;\r
+\r
+ sequence.Items.Add (element);\r
+ }\r
+\r
+ static XmlQualifiedName GetQualifiedName (Type type) \r
+ {\r
+ if (type.Equals (typeof (System.Xml.XmlNode)))\r
+ return XmlQualifiedName.Empty;\r
+\r
+ else if (type.IsSubclassOf (typeof (System.Xml.XmlNode)))\r
+ return new XmlQualifiedName ("xml");\r
+\r
+ else if (type.IsArray) {\r
+ string array_type = type.Name.Substring (0, type.Name.Length - 2);\r
+ return new XmlQualifiedName ("ArrayOf" + array_type);\r
+ } else \r
+ return GetQualifiedName (type.FullName);\r
+ }\r
+\r
+ ///<summary>\r
+ /// Populates element nodes inside a '<xs:sequence>' node.\r
+ ///</summary>\r
+ static XmlQualifiedName GetQualifiedName (string type) \r
{\r
string type_name;\r
\r
- switch (field.FieldType.FullName) {\r
+ switch (type) {\r
case "System.Uri":\r
type_name = "anyURI";\r
break;\r
break;\r
case "System.UInt64":\r
type_name = "unsignedLong"; \r
- break; \r
+ break; \r
default:\r
- type_name = String.Empty;\r
+ type_name = null;\r
break;\r
} \r
\r
- if (type_name == String.Empty)\r
- throw new Exception (String.Format ("Can't convert {0} to an applicable Schema Type", field.Name));\r
+ if (type_name == null)\r
+ return null;\r
\r
- else {\r
+ else {\r
XmlQualifiedName name = new XmlQualifiedName (type_name, xs);\r
return name; \r
} \r
}\r
}\r
}\r
-\r
-\r