2 /// MonoXSD.cs -- A reflection-based tool for dealing with XML Schema.
\r
4 /// Author: Duncan Mak (duncan@ximian.com)
\r
5 /// Lluis Sanchez Gual (lluis@ximian.com)
\r
7 /// Copyright (C) 2003, Duncan Mak,
\r
12 using System.Collections;
\r
14 using System.Reflection;
\r
16 using System.Xml.Schema;
\r
17 using System.Xml.Serialization;
\r
18 using System.CodeDom;
\r
19 using System.CodeDom.Compiler;
\r
20 using Microsoft.CSharp;
\r
22 namespace Mono.Util {
\r
26 public static readonly string helpString =
\r
27 "xsd.exe - a utility for generating schema or class files\n\n" +
\r
28 "xsd.exe <schema>.xsd /classes [/element:NAME] [/language:NAME]\n" +
\r
29 " [/namespace:NAME] [/outputdir:PATH] [/uri:NAME]\n\n" +
\r
30 "xsd.exe <assembly>.dll|<assembly>.exe [/outputdir:PATH] [/type:NAME]\n\n" +
\r
31 " /c /classes Generate classes for the specified schema.\n" +
\r
32 " /e /element:NAME Element from schema to generate code for.\n" +
\r
33 " Multiple elements can be specified.\n" +
\r
34 " /u /uri:NAME Namespace uri of the elements to generate code for.\n" +
\r
35 " /l /language:NAME The language to use for the generated code.\n" +
\r
36 " Currently, the only supported language is CS (C#).\n" +
\r
37 " /o /outputdir:PATH The directory where to generate the code or schemas.\n" +
\r
38 " /n /namespace:NAME Namespace for the generated code.\n" +
\r
39 " /t /type:NAME Type for which to generate an xml schema.\n" +
\r
40 " Multiple types can be specified.\n" +
\r
41 " /h /help Output this help.\n";
\r
43 static readonly string incorrectOrder = "Options must be specified after Assembly or schema file names";
\r
44 static readonly string duplicatedParam = "The option {0} cannot be specified more that once";
\r
45 static readonly string unknownOption = "Unknown option {0}";
\r
46 static readonly string incompatibleArgs = "Cannot mix options for generating schemas and for generatic classes";
\r
47 static readonly string invalidParams = "Invalid parameters";
\r
48 static readonly string tooManyAssem = "Only one assembly name can be specified";
\r
49 static readonly string errLoadAssembly = "Could not load assembly: {0}";
\r
50 static readonly string typeNotFound = "Type {0} not found in the specified assembly";
\r
51 static readonly string languageNotSupported = "The language {0} is not supported";
\r
54 static void Main (string [] args)
\r
56 if (args.Length < 1) {
\r
57 Console.WriteLine (helpString);
\r
58 Environment.Exit (0);
\r
63 new Driver().Run (args);
\r
65 catch (Exception ex)
\r
67 Console.WriteLine (ex.Message);
\r
68 Console.WriteLine (ex);
\r
72 string outputDir = null;
\r
75 ArrayList lookupTypes = new ArrayList();
\r
76 ArrayList assemblies = new ArrayList();
\r
78 ArrayList schemaNames = new ArrayList();
\r
79 ArrayList elements = new ArrayList();
\r
80 string language = null;
\r
81 string namesp = null;
\r
84 public void Run (string[] args)
\r
86 ArrayList unknownFiles = new ArrayList();
\r
87 bool generateClasses = false;
\r
88 bool readingFiles = true;
\r
89 bool schemasOptions = false;
\r
90 bool assemblyOptions = false;
\r
92 foreach (string arg in args)
\r
94 if (arg.EndsWith (".dll") || arg.EndsWith (".exe"))
\r
96 if (!readingFiles) throw new Exception (incorrectOrder);
\r
97 assemblies.Add (arg);
\r
98 assemblyOptions = true;
\r
101 else if (arg.EndsWith (".xsd"))
\r
103 if (!readingFiles) Error (incorrectOrder);
\r
104 schemaNames.Add (arg);
\r
105 schemasOptions = true;
\r
108 else if (!arg.StartsWith ("/") && !arg.StartsWith ("-"))
\r
110 if (!readingFiles) Error (incorrectOrder);
\r
111 unknownFiles.Add (arg);
\r
115 readingFiles = false;
\r
117 int i = arg.IndexOf (":");
\r
118 if (i == -1) i = arg.Length;
\r
119 string option = arg.Substring (1,i-1);
\r
120 string param = (i<arg.Length-1) ? arg.Substring (i+1) : "";
\r
122 if (option == "classes" || option == "c")
\r
124 if (generateClasses) Error (duplicatedParam, option);
\r
125 generateClasses = true;
\r
126 schemasOptions = true;
\r
128 else if (option == "element" || option == "e")
\r
130 elements.Add (param);
\r
131 schemasOptions = true;
\r
133 else if (option == "language" || option == "l")
\r
135 if (language != null) Error (duplicatedParam, option);
\r
137 schemasOptions = true;
\r
139 else if (option == "namespace" || option == "n")
\r
141 if (namesp != null) Error (duplicatedParam, option);
\r
143 schemasOptions = true;
\r
145 else if (option == "outputdir" || option == "o")
\r
147 if (outputDir != null) Error (duplicatedParam, option);
\r
150 else if (option == "uri" || option == "u")
\r
152 if (uri != null) Error (duplicatedParam, option);
\r
154 schemasOptions = true;
\r
156 else if (option == "type" || option == "t")
\r
158 lookupTypes.Add (param);
\r
159 assemblyOptions = true;
\r
161 else if (option == "help" || option == "h")
\r
163 Console.WriteLine (helpString);
\r
167 Error (unknownOption, option);
\r
170 if (!schemasOptions && !assemblyOptions)
\r
171 Error (invalidParams);
\r
173 if (schemasOptions && assemblyOptions)
\r
174 Error (incompatibleArgs);
\r
176 if (assemblies.Count > 1)
\r
177 Error (tooManyAssem);
\r
179 if (outputDir == null) outputDir = ".";
\r
181 if (schemasOptions)
\r
183 schemaNames.AddRange (unknownFiles);
\r
184 GenerateClasses ();
\r
188 assemblies.AddRange (unknownFiles);
\r
189 GenerateSchemas ();
\r
193 public void GenerateSchemas ()
\r
195 Assembly assembly = null;
\r
198 assembly = Assembly.LoadFrom ((string) assemblies [0]);
\r
200 catch (Exception ex)
\r
202 Error (errLoadAssembly, ex.Message);
\r
207 if (lookupTypes.Count > 0)
\r
209 types = new Type [lookupTypes.Count];
\r
210 for (int n=0; n<lookupTypes.Count; n++)
\r
212 Type t = assembly.GetType ((string)lookupTypes[n]);
\r
213 if (t == null) Error (typeNotFound, (string)lookupTypes[n]);
\r
218 types = assembly.GetExportedTypes ();
\r
220 XmlReflectionImporter ri = new XmlReflectionImporter ();
\r
221 XmlSchemas schemas = new XmlSchemas ();
\r
222 XmlSchemaExporter sx = new XmlSchemaExporter (schemas);
\r
224 foreach (Type type in types)
\r
226 XmlTypeMapping tm = ri.ImportTypeMapping (type);
\r
227 sx.ExportTypeMapping (tm);
\r
230 if (schemas.Count == 1)
\r
232 string fileName = Path.Combine (outputDir, "schema.xsd");
\r
233 WriteSchema (fileName, schemas [0]);
\r
237 for (int n=0; n<schemas.Count; n++)
\r
239 string fileName = Path.Combine (outputDir, "schema" + n + ".xsd");
\r
240 WriteSchema (fileName, schemas [n]);
\r
245 void WriteSchema (string fileName, XmlSchema schema)
\r
247 StreamWriter sw = new StreamWriter (fileName);
\r
250 Console.WriteLine ("Written file " + fileName);
\r
253 public void GenerateClasses ()
\r
255 if (language != null && language != "CS") Error (languageNotSupported, language);
\r
256 if (namesp == null) namesp = "Schemas";
\r
257 if (uri == null) uri = "";
\r
258 string targetFile = "";
\r
260 XmlSchemas schemas = new XmlSchemas();
\r
261 foreach (string fileName in schemaNames)
\r
263 StreamReader sr = new StreamReader (fileName);
\r
264 schemas.Add (XmlSchema.Read (sr, null));
\r
267 if (targetFile == "") targetFile = Path.GetFileNameWithoutExtension (fileName);
\r
268 else targetFile += "_" + Path.GetFileNameWithoutExtension (fileName);
\r
271 targetFile += ".cs";
\r
273 CodeCompileUnit cunit = new CodeCompileUnit ();
\r
274 CodeNamespace codeNamespace = new CodeNamespace (namesp);
\r
275 cunit.Namespaces.Add (codeNamespace);
\r
276 codeNamespace.Comments.Add (new CodeCommentStatement ("\nThis source code was auto-generated by MonoXSD\n"));
\r
278 // Locate elements to generate
\r
280 ArrayList qnames = new ArrayList ();
\r
281 if (elements.Count > 0)
\r
283 foreach (string name in elements)
\r
284 qnames.Add (new XmlQualifiedName (name, uri));
\r
288 foreach (XmlSchema schema in schemas) {
\r
289 if (!schema.IsCompiled) schema.Compile (null);
\r
290 foreach (XmlSchemaElement elem in schema.Elements.Values)
\r
291 qnames.Add (elem.QualifiedName);
\r
295 // Import schemas and generate the class model
\r
297 XmlSchemaImporter importer = new XmlSchemaImporter (schemas);
\r
298 XmlCodeExporter sx = new XmlCodeExporter (codeNamespace, cunit);
\r
300 ArrayList maps = new ArrayList();
\r
302 foreach (XmlQualifiedName qname in qnames)
\r
304 XmlTypeMapping tm = importer.ImportTypeMapping (qname);
\r
305 if (tm != null) maps.Add (tm);
\r
308 foreach (XmlTypeMapping tm in maps)
\r
310 sx.ExportTypeMapping (tm);
\r
313 // Generate the code
\r
315 CSharpCodeProvider provider = new CSharpCodeProvider();
\r
316 ICodeGenerator gen = provider.CreateGenerator();
\r
318 string genFile = Path.Combine (outputDir, targetFile);
\r
319 StreamWriter sw = new StreamWriter(genFile, false);
\r
320 gen.GenerateCodeFromCompileUnit (cunit, sw, new CodeGeneratorOptions());
\r
323 Console.WriteLine ("Written file " + genFile);
\r
326 public void Error (string msg)
\r
328 throw new Exception (msg);
\r
331 public void Error (string msg, string param)
\r
333 throw new Exception (string.Format(msg,param));
\r