--- /dev/null
+///\r
+/// MonoXSD.cs -- A reflection-based tool for dealing with XML Schema.\r
+///\r
+/// Author: Duncan Mak (duncan@ximian.com)\r
+/// Lluis Sanchez Gual (lluis@ximian.com)\r
+///\r
+/// Copyright (C) 2003, Duncan Mak,\r
+/// Ximian, Inc.\r
+///\r
+\r
+using System;\r
+using System.Collections;\r
+using System.IO;\r
+using System.Reflection;\r
+using System.Xml;\r
+using System.Xml.Schema;\r
+using System.Xml.Serialization;\r
+using System.CodeDom;\r
+using System.CodeDom.Compiler;\r
+using Microsoft.CSharp;\r
+\r
+namespace Mono.Util {\r
+\r
+ public class Driver\r
+ {\r
+ public static readonly string helpString =\r
+ "xsd.exe - a utility for generating schema or class files\n\n" +\r
+ "xsd.exe <schema>.xsd /classes [/element:NAME] [/language:NAME]\n" +\r
+ " [/namespace:NAME] [/outputdir:PATH] [/uri:NAME]\n\n" +\r
+ "xsd.exe <assembly>.dll|<assembly>.exe [/outputdir:PATH] [/type:NAME]\n\n" +\r
+ " /c /classes Generate classes for the specified schema.\n" +\r
+ " /e /element:NAME Element from schema to generate code for.\n" +\r
+ " Multiple elements can be specified.\n" +\r
+ " /u /uri:NAME Namespace uri of the elements to generate code for.\n" +\r
+ " /l /language:NAME The language to use for the generated code.\n" +\r
+ " Currently, the only supported language is CS (C#).\n" +\r
+ " /o /outputdir:PATH The directory where to generate the code or schemas.\n" +\r
+ " /n /namespace:NAME Namespace for the generated code.\n" +\r
+ " /t /type:NAME Type for which to generate an xml schema.\n" +\r
+ " Multiple types can be specified.\n" +\r
+ " /h /help Output this help.\n";\r
+\r
+ static readonly string incorrectOrder = "Options must be specified after Assembly or schema file names";\r
+ static readonly string duplicatedParam = "The option {0} cannot be specified more that once";\r
+ static readonly string unknownOption = "Unknown option {0}";\r
+ static readonly string incompatibleArgs = "Cannot mix options for generating schemas and for generatic classes";\r
+ static readonly string invalidParams = "Invalid parameters";\r
+ static readonly string tooManyAssem = "Only one assembly name can be specified";\r
+ static readonly string errLoadAssembly = "Could not load assembly: {0}";\r
+ static readonly string typeNotFound = "Type {0} not found in the specified assembly";\r
+ static readonly string languageNotSupported = "The language {0} is not supported";\r
+ \r
+\r
+ static void Main (string [] args)\r
+ {\r
+ if (args.Length < 1) {\r
+ Console.WriteLine (helpString);\r
+ Environment.Exit (0);\r
+ }\r
+\r
+ try\r
+ {\r
+ new Driver().Run (args);\r
+ }\r
+ catch (Exception ex)\r
+ {\r
+ Console.WriteLine (ex.Message);\r
+ Console.WriteLine (ex);\r
+ }\r
+ }\r
+\r
+ string outputDir = null;\r
+\r
+\r
+ ArrayList lookupTypes = new ArrayList();\r
+ ArrayList assemblies = new ArrayList();\r
+\r
+ ArrayList schemaNames = new ArrayList();\r
+ ArrayList elements = new ArrayList();\r
+ string language = null;\r
+ string namesp = null;\r
+ string uri = null;\r
+\r
+ public void Run (string[] args)\r
+ {\r
+ ArrayList unknownFiles = new ArrayList();\r
+ bool generateClasses = false;\r
+ bool readingFiles = true;\r
+ bool schemasOptions = false;\r
+ bool assemblyOptions = false;\r
+\r
+ foreach (string arg in args)\r
+ {\r
+ if (arg.EndsWith (".dll") || arg.EndsWith (".exe"))\r
+ {\r
+ if (!readingFiles) throw new Exception (incorrectOrder);\r
+ assemblies.Add (arg);\r
+ assemblyOptions = true;\r
+ continue;\r
+ }\r
+ else if (arg.EndsWith (".xsd"))\r
+ {\r
+ if (!readingFiles) Error (incorrectOrder);\r
+ schemaNames.Add (arg);\r
+ schemasOptions = true;\r
+ continue;\r
+ }\r
+ else if (!arg.StartsWith ("/") && !arg.StartsWith ("-"))\r
+ {\r
+ if (!readingFiles) Error (incorrectOrder);\r
+ unknownFiles.Add (arg);\r
+ continue;\r
+ }\r
+\r
+ readingFiles = false;\r
+\r
+ int i = arg.IndexOf (":");\r
+ if (i == -1) i = arg.Length;\r
+ string option = arg.Substring (1,i-1);\r
+ string param = (i<arg.Length-1) ? arg.Substring (i+1) : "";\r
+\r
+ if (option == "classes" || option == "c")\r
+ {\r
+ if (generateClasses) Error (duplicatedParam, option);\r
+ generateClasses = true;\r
+ schemasOptions = true;\r
+ }\r
+ else if (option == "element" || option == "e")\r
+ {\r
+ elements.Add (param);\r
+ schemasOptions = true;\r
+ }\r
+ else if (option == "language" || option == "l")\r
+ {\r
+ if (language != null) Error (duplicatedParam, option);\r
+ language = param;\r
+ schemasOptions = true;\r
+ }\r
+ else if (option == "namespace" || option == "n")\r
+ {\r
+ if (namesp != null) Error (duplicatedParam, option);\r
+ namesp = param;\r
+ schemasOptions = true;\r
+ }\r
+ else if (option == "outputdir" || option == "o")\r
+ {\r
+ if (outputDir != null) Error (duplicatedParam, option);\r
+ outputDir = param;\r
+ }\r
+ else if (option == "uri" || option == "u")\r
+ {\r
+ if (uri != null) Error (duplicatedParam, option);\r
+ uri = param;\r
+ schemasOptions = true;\r
+ }\r
+ else if (option == "type" || option == "t")\r
+ {\r
+ lookupTypes.Add (param);\r
+ assemblyOptions = true;\r
+ }\r
+ else if (option == "help" || option == "h")\r
+ {\r
+ Console.WriteLine (helpString);\r
+ return;\r
+ }\r
+ else\r
+ Error (unknownOption, option);\r
+ }\r
+\r
+ if (!schemasOptions && !assemblyOptions)\r
+ Error (invalidParams);\r
+\r
+ if (schemasOptions && assemblyOptions)\r
+ Error (incompatibleArgs);\r
+\r
+ if (assemblies.Count > 1)\r
+ Error (tooManyAssem);\r
+\r
+ if (outputDir == null) outputDir = ".";\r
+ \r
+ if (schemasOptions)\r
+ {\r
+ schemaNames.AddRange (unknownFiles);\r
+ GenerateClasses ();\r
+ }\r
+ else\r
+ {\r
+ assemblies.AddRange (unknownFiles);\r
+ GenerateSchemas ();\r
+ }\r
+ }\r
+\r
+ public void GenerateSchemas ()\r
+ {\r
+ Assembly assembly = null;\r
+ try\r
+ {\r
+ assembly = Assembly.LoadFrom ((string) assemblies [0]);\r
+ }\r
+ catch (Exception ex)\r
+ {\r
+ Error (errLoadAssembly, ex.Message);\r
+ }\r
+ \r
+ Type[] types;\r
+ \r
+ if (lookupTypes.Count > 0)\r
+ {\r
+ types = new Type [lookupTypes.Count];\r
+ for (int n=0; n<lookupTypes.Count; n++)\r
+ {\r
+ Type t = assembly.GetType ((string)lookupTypes[n]);\r
+ if (t == null) Error (typeNotFound, (string)lookupTypes[n]);\r
+ types[n] = t;\r
+ }\r
+ }\r
+ else\r
+ types = assembly.GetExportedTypes ();\r
+\r
+ XmlReflectionImporter ri = new XmlReflectionImporter ();\r
+ XmlSchemas schemas = new XmlSchemas ();\r
+ XmlSchemaExporter sx = new XmlSchemaExporter (schemas);\r
+\r
+ foreach (Type type in types)\r
+ {\r
+ XmlTypeMapping tm = ri.ImportTypeMapping (type);\r
+ sx.ExportTypeMapping (tm);\r
+ }\r
+\r
+ if (schemas.Count == 1)\r
+ {\r
+ string fileName = Path.Combine (outputDir, "schema.xsd");\r
+ WriteSchema (fileName, schemas [0]);\r
+ }\r
+ else\r
+ {\r
+ for (int n=0; n<schemas.Count; n++)\r
+ {\r
+ string fileName = Path.Combine (outputDir, "schema" + n + ".xsd");\r
+ WriteSchema (fileName, schemas [n]);\r
+ }\r
+ }\r
+ }\r
+\r
+ void WriteSchema (string fileName, XmlSchema schema)\r
+ {\r
+ StreamWriter sw = new StreamWriter (fileName);\r
+ schema.Write (sw);\r
+ sw.Close ();\r
+ Console.WriteLine ("Written file " + fileName);\r
+ }\r
+ \r
+ public void GenerateClasses ()\r
+ {\r
+ if (language != null && language != "CS") Error (languageNotSupported, language);\r
+ if (namesp == null) namesp = "Schemas";\r
+ if (uri == null) uri = "";\r
+ string targetFile = "";\r
+\r
+ XmlSchemas schemas = new XmlSchemas();\r
+ foreach (string fileName in schemaNames)\r
+ {\r
+ StreamReader sr = new StreamReader (fileName);\r
+ schemas.Add (XmlSchema.Read (sr, null));\r
+ sr.Close ();\r
+\r
+ if (targetFile == "") targetFile = Path.GetFileNameWithoutExtension (fileName);\r
+ else targetFile += "_" + Path.GetFileNameWithoutExtension (fileName);\r
+ }\r
+\r
+ targetFile += ".cs";\r
+\r
+ CodeCompileUnit cunit = new CodeCompileUnit ();\r
+ CodeNamespace codeNamespace = new CodeNamespace (namesp);\r
+ cunit.Namespaces.Add (codeNamespace);\r
+ codeNamespace.Comments.Add (new CodeCommentStatement ("\nThis source code was auto-generated by MonoXSD\n"));\r
+\r
+ // Locate elements to generate\r
+\r
+ ArrayList qnames = new ArrayList ();\r
+ if (elements.Count > 0)\r
+ {\r
+ foreach (string name in elements)\r
+ qnames.Add (new XmlQualifiedName (name, uri));\r
+ }\r
+ else\r
+ {\r
+ foreach (XmlSchema schema in schemas) {\r
+ foreach (XmlSchemaElement elem in schema.Elements)\r
+ qnames.Add (elem.QualifiedName);\r
+ }\r
+ }\r
+\r
+ // Import schemas and generate the class model\r
+\r
+ XmlSchemaImporter importer = new XmlSchemaImporter (schemas);\r
+ XmlCodeExporter sx = new XmlCodeExporter (codeNamespace, cunit);\r
+\r
+ ArrayList maps = new ArrayList();\r
+\r
+ foreach (XmlQualifiedName qname in qnames)\r
+ {\r
+ XmlTypeMapping tm = importer.ImportTypeMapping (qname);\r
+ if (tm != null) maps.Add (tm);\r
+ }\r
+ \r
+ foreach (XmlTypeMapping tm in maps)\r
+ {\r
+ sx.ExportTypeMapping (tm);\r
+ }\r
+\r
+ // Generate the code\r
+ \r
+ CSharpCodeProvider provider = new CSharpCodeProvider();\r
+ ICodeGenerator gen = provider.CreateGenerator();\r
+\r
+ string genFile = Path.Combine (outputDir, targetFile);\r
+ StreamWriter sw = new StreamWriter(genFile, false);\r
+ gen.GenerateCodeFromCompileUnit (cunit, sw, new CodeGeneratorOptions());\r
+ sw.Close();\r
+\r
+ Console.WriteLine ("Written file " + genFile);\r
+ }\r
+\r
+ public void Error (string msg)\r
+ {\r
+ throw new Exception (msg);\r
+ }\r
+\r
+ public void Error (string msg, string param)\r
+ {\r
+ throw new Exception (string.Format(msg,param));\r
+ }\r
+ }\r
+}\r