From aff29bb9226e1059fbe2ee2c98f0b91e17c51fe9 Mon Sep 17 00:00:00 2001 From: Michael Ganss Date: Wed, 23 Dec 2020 16:03:55 +0100 Subject: [PATCH] Add configurable comment languages Add System.Xml.Schema namespace to usings Fix #160 --- XmlSchemaClassGenerator.Console/Program.cs | 8 ++++++- XmlSchemaClassGenerator.Tests/Compiler.cs | 5 +++- XmlSchemaClassGenerator.Tests/XmlTests.cs | 6 ++++- .../XsdElsterDatenabholung5.cs | 24 +++++++------------ XmlSchemaClassGenerator/CodeUtilities.cs | 1 + XmlSchemaClassGenerator/Generator.cs | 5 ++++ .../GeneratorConfiguration.cs | 6 +++++ XmlSchemaClassGenerator/TypeModel.cs | 24 ++++++++++--------- 8 files changed, 50 insertions(+), 29 deletions(-) diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index ca4d7f8f..bd9effea 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -49,6 +49,8 @@ static void Main(string[] args) var collectionSettersMode = CollectionSettersMode.Private; var doNotForceIsNullable = false; var compactTypeNames = false; + var commentLanguages = new[] { "en" }; + var supportedCommentLanguages = new[] { "en", "de" }; var options = new OptionSet { { "h|help", "show this message and exit", v => showHelp = v != null }, @@ -115,7 +117,9 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { "sf|separateFiles", "generate a separate file for each class (default is false)", v => separateClasses = v != null }, { "sg|separateSubstitutes", "generate a separate property for each element of a substitution group (default is false)", v => separateSubstitutes = v != null }, { "dnfin|doNotForceIsNullable", "do not force generator to emit IsNullable = true in XmlElement annotation for nillable elements when element is nullable (minOccurs < 1 or parent element is choice) (default is false)", v => doNotForceIsNullable = v != null }, - { "cn|compactTypeNames", "use type names without namespace qualifier for types in the using list (default is false)", v => compactTypeNames = v != null } + { "cn|compactTypeNames", "use type names without namespace qualifier for types in the using list (default is false)", v => compactTypeNames = v != null }, + { "cl|commentLanguages=", $"comment languages to use (default is {string.Join(", ", commentLanguages)}; supported are {string.Join(", ", supportedCommentLanguages)})", + v => commentLanguages = v.Split(',').Select(l => l.Trim()).ToArray() } }; var globsAndUris = options.Parse(args); @@ -190,6 +194,8 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l CompactTypeNames = compactTypeNames }; + generator.CommentLanguages.AddRange(commentLanguages); + if (pclCompatible) { generator.UseXElementForAny = true; diff --git a/XmlSchemaClassGenerator.Tests/Compiler.cs b/XmlSchemaClassGenerator.Tests/Compiler.cs index 0bc7ae8b..8b5ad9a9 100644 --- a/XmlSchemaClassGenerator.Tests/Compiler.cs +++ b/XmlSchemaClassGenerator.Tests/Compiler.cs @@ -109,9 +109,12 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen CollectionType = generatorPrototype.CollectionType, CollectionImplementationType = generatorPrototype.CollectionImplementationType, SeparateSubstitutes = generatorPrototype.SeparateSubstitutes, - CompactTypeNames = generatorPrototype.CompactTypeNames + CompactTypeNames = generatorPrototype.CompactTypeNames, }; + gen.CommentLanguages.Clear(); + gen.CommentLanguages.AddRange(generatorPrototype.CommentLanguages); + output.Configuration = gen.Configuration; gen.Generate(files); diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 73607340..8fb7edc1 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -57,6 +57,9 @@ private static IEnumerable ConvertXml(string name, IEnumerable x DoNotForceIsNullable = generatorPrototype.DoNotForceIsNullable }; + gen.CommentLanguages.Clear(); + gen.CommentLanguages.AddRange(generatorPrototype.CommentLanguages); + var set = new XmlSchemaSet(); foreach (var xsd in xsds) @@ -980,7 +983,8 @@ public void ComplexTypeWithAttributeGroupExtension() NamespaceProvider = new NamespaceProvider { GenerateNamespace = key => "Test" - } + }, + CommentLanguages = { "de", "en" } }; var contents = ConvertXml(nameof(ComplexTypeWithAttributeGroupExtension), xsd, generator); diff --git a/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs b/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs index 46d191c2..d5378357 100644 --- a/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs +++ b/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs @@ -41,22 +41,16 @@ public void CanGenerateClasses() { GenerateNamespace = key => { - switch (Path.GetFileName(key.Source.LocalPath)) + return (Path.GetFileName(key.Source.LocalPath)) switch { - case "th000008_extern.xsd": - case "ndh000010_extern.xsd": - case "headerbasis000002.xsd": - return "Elster.Basis"; - case "datenabholung_5.xsd": - case "elster0810_datenabholung_5.xsd": - return key.XmlSchemaNamespace switch - { - "http://www.elster.de/2002/XMLSchema" => "Elster.Datenabholung5", - _ => throw new NotSupportedException(string.Format("Namespace {0} for schema {1}", key.XmlSchemaNamespace, key.Source)), - }; - default: - throw new NotSupportedException(string.Format("Namespace {0} for schema {1}", key.XmlSchemaNamespace, key.Source)); - } + "th000008_extern.xsd" or "ndh000010_extern.xsd" or "headerbasis000002.xsd" => "Elster.Basis", + "datenabholung_5.xsd" or "elster0810_datenabholung_5.xsd" => key.XmlSchemaNamespace switch + { + "http://www.elster.de/2002/XMLSchema" => "Elster.Datenabholung5", + _ => throw new NotSupportedException(string.Format("Namespace {0} for schema {1}", key.XmlSchemaNamespace, key.Source)), + }, + _ => throw new NotSupportedException(string.Format("Namespace {0} for schema {1}", key.XmlSchemaNamespace, key.Source)), + }; } } }; diff --git a/XmlSchemaClassGenerator/CodeUtilities.cs b/XmlSchemaClassGenerator/CodeUtilities.cs index e99d82a8..52fa7f19 100644 --- a/XmlSchemaClassGenerator/CodeUtilities.cs +++ b/XmlSchemaClassGenerator/CodeUtilities.cs @@ -373,6 +373,7 @@ public static KeyValuePair ParseNamespace(string nsArg, st ("System.ComponentModel.DataAnnotations", c => c.CompactTypeNames && (c.DataAnnotationMode != DataAnnotationMode.None || c.EntityFramework)), ("System.Diagnostics", c => c.CompactTypeNames && c.GenerateDebuggerStepThroughAttribute), ("System.Linq", c => c.EnableDataBinding), + ("System.Xml.Schema", c => c.CompactTypeNames), ("System.Xml.Serialization", c => c.CompactTypeNames) }; diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 20b73568..5464eba1 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -265,6 +265,11 @@ public bool CompactTypeNames set { _configuration.CompactTypeNames = value; } } + public List CommentLanguages + { + get { return _configuration.CommentLanguages; } + } + static Generator() { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index 5acee3e9..041d4654 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -1,5 +1,6 @@ using System; using System.CodeDom; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text.RegularExpressions; @@ -279,5 +280,10 @@ public void WriteLog(string message) /// Generates type names without namespace qualifiers for namespaces in using list /// public bool CompactTypeNames { get; set; } + + /// + /// The language identifiers comments will be generated for, e.g. "en", "de-DE". + /// + public List CommentLanguages { get; } = new List(); } } diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index 84928b18..14d96403 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -38,7 +38,7 @@ public static CodeNamespace Generate(string namespaceName, IEnumerable n.Condition(conf))) + foreach (var (Namespace, Condition) in CodeUtilities.UsingNamespaces.Where(n => n.Condition(conf)).OrderBy(n => n.Namespace)) codeNamespace.Imports.Add(new CodeNamespaceImport(Namespace)); var typeModels = parts.SelectMany(x => x.Types.Values).ToList(); @@ -62,14 +62,16 @@ public class DocumentationModel public string Text { get; set; } public static bool DisableComments { get; set; } - public static IEnumerable GetComments(IList docs) + public static IEnumerable GetComments(IList docs, GeneratorConfiguration conf) { if (DisableComments || docs.Count == 0) yield break; yield return new CodeCommentStatement("", true); - foreach (var doc in docs.OrderBy(d => d.Language)) + foreach (var doc in docs + .Where(d => conf.CommentLanguages.Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase))) + .OrderBy(d => d.Language)) { var text = doc.Text; var comment = string.Format(@"{1}", @@ -84,7 +86,7 @@ public static void AddDescription(CodeAttributeDeclarationCollection attributes, { if (!conf.GenerateDescriptionAttribute || DisableComments || !docs.Any()) return; - var doc = GetSingleDoc(docs); + var doc = GetSingleDoc(docs.Where(d => conf.CommentLanguages.Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase)))); if (doc != null) { @@ -127,7 +129,7 @@ public virtual CodeTypeDeclaration Generate() { var typeDeclaration = new CodeTypeDeclaration { Name = Name }; - typeDeclaration.Comments.AddRange(DocumentationModel.GetComments(Documentation).ToArray()); + typeDeclaration.Comments.AddRange(DocumentationModel.GetComments(Documentation, Configuration).ToArray()); DocumentationModel.AddDescription(typeDeclaration.CustomAttributes, Documentation, Configuration); @@ -387,7 +389,7 @@ public override CodeTypeDeclaration Generate() } } - member.Comments.AddRange(DocumentationModel.GetComments(docs).ToArray()); + member.Comments.AddRange(DocumentationModel.GetComments(docs, Configuration).ToArray()); member.CustomAttributes.Add(attribute); classDeclaration.Members.Add(member); @@ -766,7 +768,7 @@ private void AddDocs(CodeTypeMember member) member.CustomAttributes.AddRange(simpleType.GetRestrictionAttributes().ToArray()); } - member.Comments.AddRange(DocumentationModel.GetComments(docs).ToArray()); + member.Comments.AddRange(DocumentationModel.GetComments(docs, Configuration).ToArray()); } private CodeAttributeDeclaration CreateDefaultValueAttribute(CodeTypeReference typeReference, CodeExpression defaultValueExpression) @@ -969,7 +971,7 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi specifiedMember.Attributes = MemberAttributes.Public; var specifiedDocs = new[] { new DocumentationModel { Language = "en", Text = string.Format("Gets or sets a value indicating whether the {0} property is specified.", Name) }, new DocumentationModel { Language = "de", Text = string.Format("Ruft einen Wert ab, der angibt, ob die {0}-Eigenschaft spezifiziert ist, oder legt diesen fest.", Name) } }; - specifiedMember.Comments.AddRange(DocumentationModel.GetComments(specifiedDocs).ToArray()); + specifiedMember.Comments.AddRange(DocumentationModel.GetComments(specifiedDocs, Configuration).ToArray()); typeDeclaration.Members.Add(specifiedMember); var specifiedMemberPropertyModel = new PropertyModel(Configuration) @@ -1078,7 +1080,7 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi var specifiedDocs = new[] { new DocumentationModel { Language = "en", Text = string.Format("Gets a value indicating whether the {0} collection is empty.", Name) }, new DocumentationModel { Language = "de", Text = string.Format("Ruft einen Wert ab, der angibt, ob die {0}-Collection leer ist.", Name) } }; - specifiedProperty.Comments.AddRange(DocumentationModel.GetComments(specifiedDocs).ToArray()); + specifiedProperty.Comments.AddRange(DocumentationModel.GetComments(specifiedDocs, Configuration).ToArray()); Configuration.MemberVisitor(specifiedProperty, this); @@ -1098,7 +1100,7 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi constructor = new CodeConstructor { Attributes = MemberAttributes.Public | MemberAttributes.Final }; var constructorDocs = new[] { new DocumentationModel { Language = "en", Text = string.Format(@"Initializes a new instance of the class.", typeDeclaration.Name) }, new DocumentationModel { Language = "de", Text = string.Format(@"Initialisiert eine neue Instanz der Klasse.", typeDeclaration.Name) } }; - constructor.Comments.AddRange(DocumentationModel.GetComments(constructorDocs).ToArray()); + constructor.Comments.AddRange(DocumentationModel.GetComments(constructorDocs, Configuration).ToArray()); typeDeclaration.Members.Add(constructor); } @@ -1341,7 +1343,7 @@ public override CodeTypeDeclaration Generate() docs.Add(obsolete); } - member.Comments.AddRange(DocumentationModel.GetComments(docs).ToArray()); + member.Comments.AddRange(DocumentationModel.GetComments(docs, Configuration).ToArray()); enumDeclaration.Members.Add(member); }