diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index 8ef63a1e..be10767f 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -36,6 +36,7 @@ static void Main(string[] args) var generateDebuggerStepThroughAttribute = true; var disableComments = false; var doNotUseUnderscoreInPrivateMemberNames = false; + var generateDescriptionAttribute = true; var options = new OptionSet { { "h|help", "show this message and exit", v => showHelp = v != null }, @@ -79,6 +80,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { "dst|debuggerStepThrough", "generate DebuggerStepThroughAttribute (default is enabled)", v => generateDebuggerStepThroughAttribute = v != null }, { "dc|disableComments", "do not include comments from xsd", v => disableComments = v != null }, { "nu|noUnderscore", "do not generate underscore in private member name (default is false)", v => doNotUseUnderscoreInPrivateMemberNames = v != null }, + { "da|description", "generate DescriptionAttribute (default is true)", v => generateDescriptionAttribute = v != null }, }; var files = options.Parse(args); @@ -122,6 +124,8 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l TextValuePropertyName = textValuePropertyName, GenerateDebuggerStepThroughAttribute = generateDebuggerStepThroughAttribute, DisableComments = disableComments, + GenerateDescriptionAttribute = generateDescriptionAttribute, + DoNotUseUnderscoreInPrivateMemberNames = doNotUseUnderscoreInPrivateMemberNames }; if (pclCompatible) @@ -131,8 +135,9 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l generator.GenerateSerializableAttribute = false; generator.GenerateDebuggerStepThroughAttribute = false; generator.DataAnnotationMode = DataAnnotationMode.None; + generator.GenerateDescriptionAttribute = false; } - generator.DoNotUseUnderscoreInPrivateMemberNames = doNotUseUnderscoreInPrivateMemberNames; + if (verbose) { generator.Log = s => System.Console.Out.WriteLine(s); } generator.Generate(files); diff --git a/XmlSchemaClassGenerator.Tests/Compiler.cs b/XmlSchemaClassGenerator.Tests/Compiler.cs index 155e530e..68f34ab1 100644 --- a/XmlSchemaClassGenerator.Tests/Compiler.cs +++ b/XmlSchemaClassGenerator.Tests/Compiler.cs @@ -62,7 +62,8 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen GenerateDesignerCategoryAttribute = false, EntityFramework = false, GenerateInterfaces = true, - NamespacePrefix = name + NamespacePrefix = name, + GenerateDescriptionAttribute = true }; var output = new FileWatcherOutputWriter(Path.Combine("output", name)); @@ -78,6 +79,7 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen EntityFramework = generatorPrototype.EntityFramework, GenerateInterfaces = generatorPrototype.GenerateInterfaces, MemberVisitor = generatorPrototype.MemberVisitor, + GenerateDescriptionAttribute = generatorPrototype.GenerateDescriptionAttribute }; gen.Generate(files); diff --git a/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs b/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs index 0199e374..0a762ecd 100644 --- a/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs +++ b/XmlSchemaClassGenerator.Tests/XsdElsterDatenabholung5.cs @@ -35,6 +35,7 @@ public void CanGenerateClasses() NamingScheme = NamingScheme.Direct, DataAnnotationMode = DataAnnotationMode.None, EmitOrder = true, + GenerateDescriptionAttribute = true, NamespaceProvider = new NamespaceProvider { GenerateNamespace = key => diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 9da84e2a..97149406 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -148,6 +148,12 @@ public bool GenerateInterfaces set { _configuration.GenerateInterfaces = value; } } + public bool GenerateDescriptionAttribute + { + get { return _configuration.GenerateDescriptionAttribute; } + set { _configuration.GenerateDescriptionAttribute = value; } + } + public CodeTypeReferenceOptions CodeTypeReferenceOptions { get { return _configuration.CodeTypeReferenceOptions; } diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index fb857f62..9c18001a 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -124,6 +124,10 @@ public GeneratorConfiguration() /// Generate interfaces for groups and attribute groups /// public bool GenerateInterfaces { get; set; } + /// + /// Generate from XML comments. + /// + public bool GenerateDescriptionAttribute { get; set; } /// /// Generator Code reference options diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index 11b45136..3a3af2b2 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using System.Text.RegularExpressions; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; @@ -77,12 +78,34 @@ public static IEnumerable GetComments(IEnumerable{1}", - string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language), CodeUtilities.NormalizeNewlines(text)); + string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language), CodeUtilities.NormalizeNewlines(text).Trim()); yield return new CodeCommentStatement(comment, true); } yield return new CodeCommentStatement("", true); } + + public static void AddDescription(CodeAttributeDeclarationCollection attributes, IEnumerable docs, GeneratorConfiguration conf) + { + if (!conf.GenerateDescriptionAttribute || DisableComments || !docs.Any()) return; + + var doc = GetSingleDoc(docs); + + if (doc != null) + { + var descriptionAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(DescriptionAttribute), conf.CodeTypeReferenceOptions), + new CodeAttributeArgument(new CodePrimitiveExpression(Regex.Replace(doc.Text, @"\s+", " ").Trim()))); + attributes.Add(descriptionAttribute); + } + } + + private static DocumentationModel GetSingleDoc(IEnumerable docs) + { + if (docs.Count() == 1) return docs.Single(); + var englishDoc = docs.Where(d => string.IsNullOrEmpty(d.Language) || d.Language.StartsWith("en", StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + if (englishDoc != null) return englishDoc; + return docs.FirstOrDefault(); + } } public abstract class TypeModel @@ -110,6 +133,8 @@ public virtual CodeTypeDeclaration Generate() typeDeclaration.Comments.AddRange(DocumentationModel.GetComments(Documentation).ToArray()); + DocumentationModel.AddDescription(typeDeclaration.CustomAttributes, Documentation, Configuration); + var generatedAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(GeneratedCodeAttribute), Configuration.CodeTypeReferenceOptions), new CodeAttributeArgument(new CodePrimitiveExpression(Configuration.Version.Title)), new CodeAttributeArgument(new CodePrimitiveExpression(Configuration.Version.Version))); @@ -609,6 +634,8 @@ private void AddDocs(CodeTypeMember member) { var docs = new List(Documentation); + DocumentationModel.AddDescription(member.CustomAttributes, docs, Configuration); + if (PropertyType is SimpleModel simpleType) { docs.AddRange(simpleType.Documentation); @@ -1071,6 +1098,8 @@ public override CodeTypeDeclaration Generate() var member = new CodeMemberField { Name = val.Name }; var docs = new List(val.Documentation); + DocumentationModel.AddDescription(member.CustomAttributes, docs, Configuration); + if (val.Name != val.Value) // illegal identifier chars in value { var enumAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlEnumAttribute), Configuration.CodeTypeReferenceOptions),