diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index a6ee950d..bdb18e61 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -43,6 +43,7 @@ static void Main(string[] args) var enableUpaCheck = true; var generateComplexTypesForCollections = true; var useShouldSerialize = false; + var separateClasses = false; var options = new OptionSet { { "h|help", "show this message and exit", v => showHelp = v != null }, @@ -91,6 +92,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { "da|description", "generate DescriptionAttribute (default is true)", v => generateDescriptionAttribute = v != null }, { "cc|complexTypesForCollections", "generate complex types for collections (default is true)", v => generateComplexTypesForCollections = v != null }, { "s|useShouldSerialize", "use ShouldSerialize pattern instead of Specified pattern (default is false)", v => useShouldSerialize = v != null }, + { "sf|separateFiles", "generate a separate file for each class (default is false)", v => separateClasses = v != null }, }; var globsAndUris = options.Parse(args); @@ -156,7 +158,8 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l PrivateMemberPrefix = doNotUseUnderscoreInPrivateMemberNames ? "" : "_", EnableUpaCheck = enableUpaCheck, GenerateComplexTypesForCollections = generateComplexTypesForCollections, - UseShouldSerializePattern = useShouldSerialize + UseShouldSerializePattern = useShouldSerialize, + SeparateClasses = separateClasses }; if (pclCompatible) diff --git a/XmlSchemaClassGenerator.Tests/Compiler.cs b/XmlSchemaClassGenerator.Tests/Compiler.cs index 890e3369..47a4639f 100644 --- a/XmlSchemaClassGenerator.Tests/Compiler.cs +++ b/XmlSchemaClassGenerator.Tests/Compiler.cs @@ -84,7 +84,7 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen TextValuePropertyName = "Value" }; - var output = new FileWatcherOutputWriter(Path.Combine("output", name)); + var output = generatorPrototype.OutputWriter as FileWatcherOutputWriter ?? new FileWatcherOutputWriter(Path.Combine("output", name)); var gen = new Generator { @@ -102,9 +102,12 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen GenerateDescriptionAttribute = generatorPrototype.GenerateDescriptionAttribute, CodeTypeReferenceOptions = generatorPrototype.CodeTypeReferenceOptions, TextValuePropertyName = generatorPrototype.TextValuePropertyName, - EmitOrder = generatorPrototype.EmitOrder + EmitOrder = generatorPrototype.EmitOrder, + SeparateClasses = generatorPrototype.SeparateClasses }; + output.Configuration = gen.Configuration; + gen.Generate(files); return CompileFiles(name, output.Files); diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 59081d24..6733308c 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -205,6 +205,21 @@ public void TestTableau() TestSamples("Tableau", TableauPattern); } + [Fact, TestPriority(1)] + [UseCulture("en-US")] + public void TestSeparateClasses() + { + var output = new FileWatcherOutputWriter(Path.Combine("output", "Tableau.Separate")); + Compiler.Generate("Tableau.Separate", TableauPattern, + new Generator + { + OutputWriter = output, + SeparateClasses = true, + EnableDataBinding = true + }); + TestSamples("Tableau.Separate", TableauPattern); + } + [Fact, TestPriority(1)] [UseCulture("en-US")] public void TestDtsx() diff --git a/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs b/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs index 1b77a56b..46d191c2 100644 --- a/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs +++ b/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs @@ -36,6 +36,7 @@ public void CanGenerateClasses() DataAnnotationMode = DataAnnotationMode.None, EmitOrder = true, GenerateDescriptionAttribute = true, + SeparateClasses = true, NamespaceProvider = new NamespaceProvider { GenerateNamespace = key => @@ -76,7 +77,7 @@ public void CanGenerateClasses() public void CanCompileClasses() { var inputPath = GetOutputPath("CanGenerateClasses"); - var fileNames = new DirectoryInfo(inputPath).GetFiles("*.cs").Select(x => x.FullName).ToArray(); + var fileNames = new DirectoryInfo(inputPath).GetFiles("*.cs", SearchOption.AllDirectories).Select(x => x.FullName).ToArray(); var assembly = Compiler.CompileFiles("Elster.Test", fileNames); assembly.GetType("Elster.Datenabholung5.Elster", true); diff --git a/XmlSchemaClassGenerator.sln b/XmlSchemaClassGenerator.sln index a0b92761..23fb93ad 100644 --- a/XmlSchemaClassGenerator.sln +++ b/XmlSchemaClassGenerator.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29920.165 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XmlSchemaClassGenerator", "XmlSchemaClassGenerator\XmlSchemaClassGenerator.csproj", "{ECC57F00-DEED-4744-A65A-89222DEA441A}" EndProject diff --git a/XmlSchemaClassGenerator/FileOutputWriter.cs b/XmlSchemaClassGenerator/FileOutputWriter.cs index e87dc389..a5256a1d 100644 --- a/XmlSchemaClassGenerator/FileOutputWriter.cs +++ b/XmlSchemaClassGenerator/FileOutputWriter.cs @@ -1,6 +1,9 @@ -using System.CodeDom; +using System; +using System.CodeDom; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text.RegularExpressions; namespace XmlSchemaClassGenerator { @@ -30,10 +33,16 @@ public override void Write(CodeNamespace cn) var cu = new CodeCompileUnit(); cu.Namespaces.Add(cn); - var path = Path.Combine(OutputDirectory, cn.Name + ".cs"); - Configuration?.WriteLog(path); - - WriteFile(path, cu); + if (Configuration?.SeparateClasses == true) + { + WriteSeparateFiles(cn); + } + else + { + var path = Path.Combine(OutputDirectory, cn.Name + ".cs"); + Configuration?.WriteLog(path); + WriteFile(path, cu); + } } protected virtual void WriteFile(string path, CodeCompileUnit cu) @@ -56,5 +65,31 @@ protected virtual void WriteFile(string path, CodeCompileUnit cu) fs.Dispose(); } } + + private void WriteSeparateFiles(CodeNamespace cn) + { + var dirPath = Path.Combine(OutputDirectory, ValidateName(cn.Name)); + var ccu = new CodeCompileUnit(); + var cns = new CodeNamespace(ValidateName(cn.Name)); + + Directory.CreateDirectory(dirPath); + + cns.Imports.AddRange(cn.Imports.Cast().ToArray()); + cns.Comments.AddRange(cn.Comments); + ccu.Namespaces.Add(cns); + + foreach (CodeTypeDeclaration ctd in cn.Types) + { + var path = Path.Combine(dirPath, ctd.Name + ".cs"); + cns.Types.Clear(); + cns.Types.Add(ctd); + Configuration?.WriteLog(path); + WriteFile(path, ccu); + } + } + + static readonly Regex InvalidCharacters = new Regex($"[{string.Join("", Path.GetInvalidFileNameChars())}]", RegexOptions.Compiled); + + private string ValidateName(string name) => InvalidCharacters.Replace(name, "_"); } } \ No newline at end of file diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index fb1ea3fc..1ece78d4 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -12,6 +12,8 @@ public class Generator { private readonly GeneratorConfiguration _configuration = new GeneratorConfiguration(); + public GeneratorConfiguration Configuration => _configuration; + public NamespaceProvider NamespaceProvider { get { return _configuration.NamespaceProvider; } @@ -214,12 +216,18 @@ public string PrivateMemberPrefix public bool EnableUpaCheck { get { return _configuration.EnableUpaCheck; } - set { _configuration.EnableUpaCheck = value; } - } - - public void Generate(IEnumerable files) - { - var set = new XmlSchemaSet(); + set { _configuration.EnableUpaCheck = value; } + } + + public bool SeparateClasses + { + get { return _configuration.SeparateClasses; } + set { _configuration.SeparateClasses = value; } + } + + public void Generate(IEnumerable files) + { + var set = new XmlSchemaSet(); var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }; var readers = files.Select(f => XmlReader.Create(f, settings)); diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index a39b5b32..2e81715e 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -241,8 +241,13 @@ public void WriteLog(string message) /// } /// /// public class componentType {} - /// - /// - public bool GenerateComplexTypesForCollections { get; set; } = true; - } -} + /// + /// + public bool GenerateComplexTypesForCollections { get; set; } = true; + + /// + /// Separates each class into an individual file + /// + public bool SeparateClasses { get; set; } = false; + } +} diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index 297db242..3d083cc4 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -285,7 +285,7 @@ public override CodeTypeDeclaration Generate() if (IsAbstract) classDeclaration.TypeAttributes |= System.Reflection.TypeAttributes.Abstract; - if (Configuration.EnableDataBinding) + if (Configuration.EnableDataBinding && !(BaseClass is ClassModel)) { var propertyChangedEvent = new CodeMemberEvent() {