diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index 556ed7cc..85789e0b 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -91,7 +91,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { var xn = key.XmlSchemaNamespace; var name = string.Join(".", xn.Split('/').Where(p => Regex.IsMatch(p, @"^[A-Za-z]+$") && p != "schema") - .Select(n => Generator.ToTitleCase(n, NamingScheme.PascalCase))); + .Select(n => n.ToTitleCase(NamingScheme.PascalCase))); if (!string.IsNullOrEmpty(namespacePrefix)) { name = namespacePrefix + (string.IsNullOrEmpty(name) ? "" : ("." + name)); } return name; }); diff --git a/XmlSchemaClassGenerator/CodeUtilities.cs b/XmlSchemaClassGenerator/CodeUtilities.cs index 72e148b7..9a43bf69 100644 --- a/XmlSchemaClassGenerator/CodeUtilities.cs +++ b/XmlSchemaClassGenerator/CodeUtilities.cs @@ -9,20 +9,6 @@ namespace XmlSchemaClassGenerator { public static class CodeUtilities { - public static string ToNormalizedEnumName(this string name) - { - name = name.Trim().Replace(' ', '_').Replace('\t', '_'); - if (string.IsNullOrEmpty(name)) - { - return "Item"; - } - if (!char.IsLetter(name[0])) - { - return string.Format("Item{0}", name); - } - return name; - } - // Match non-letter followed by letter static Regex PascalCaseRegex = new Regex(@"[^\p{L}]\p{L}", RegexOptions.Compiled); diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 1b3c77bc..6b90caf9 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -3,17 +3,12 @@ using System.CodeDom.Compiler; using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using System.Xml.Schema; -using System.Xml.Serialization; namespace XmlSchemaClassGenerator { @@ -27,6 +22,12 @@ public NamespaceProvider NamespaceProvider set { _configuration.NamespaceProvider = value; } } + public NamingProvider NameingProvider + { + get { return _configuration.NamingProvider; } + set { _configuration.NamingProvider = value; } + } + public string NamespacePrefix { get { return _configuration.NamespacePrefix; } @@ -234,113 +235,9 @@ private string BuildNamespace(Uri source, string xmlNamespace) throw new Exception(string.Format("Namespace {0} not provided through map or generator.", xmlNamespace)); } - private static readonly Dictionary InvalidChars = CreateInvalidChars(); - - private static Dictionary CreateInvalidChars() - { - var invalidChars = new Dictionary - { - ['\x00'] = "Null", - ['\x01'] = "StartOfHeading", - ['\x02'] = "StartOfText", - ['\x03'] = "EndOfText", - ['\x04'] = "EndOfTransmission", - ['\x05'] = "Enquiry", - ['\x06'] = "Acknowledge", - ['\x07'] = "Bell", - ['\x08'] = "Backspace", - ['\x09'] = "HorizontalTab", - ['\x0A'] = "LineFeed", - ['\x0B'] = "VerticalTab", - ['\x0C'] = "FormFeed", - ['\x0D'] = "CarriageReturn", - ['\x0E'] = "ShiftOut", - ['\x0F'] = "ShiftIn", - ['\x10'] = "DataLinkEscape", - ['\x11'] = "DeviceControl1", - ['\x12'] = "DeviceControl2", - ['\x13'] = "DeviceControl3", - ['\x14'] = "DeviceControl4", - ['\x15'] = "NegativeAcknowledge", - ['\x16'] = "SynchronousIdle", - ['\x17'] = "EndOfTransmissionBlock", - ['\x18'] = "Cancel", - ['\x19'] = "EndOfMedium", - ['\x1A'] = "Substitute", - ['\x1B'] = "Escape", - ['\x1C'] = "FileSeparator", - ['\x1D'] = "GroupSeparator", - ['\x1E'] = "RecordSeparator", - ['\x1F'] = "UnitSeparator", - //invalidChars['\x20'] = "Space"; - ['\x21'] = "ExclamationMark", - ['\x22'] = "Quote", - ['\x23'] = "Hash", - ['\x24'] = "Dollar", - ['\x25'] = "Percent", - ['\x26'] = "Ampersand", - ['\x27'] = "SingleQuote", - ['\x28'] = "LeftParenthesis", - ['\x29'] = "RightParenthesis", - ['\x2A'] = "Asterisk", - ['\x2B'] = "Plus", - ['\x2C'] = "Comma", - //invalidChars['\x2D'] = "Minus"; - ['\x2E'] = "Period", - ['\x2F'] = "Slash", - ['\x3A'] = "Colon", - ['\x3B'] = "Semicolon", - ['\x3C'] = "LessThan", - ['\x3D'] = "Equal", - ['\x3E'] = "GreaterThan", - ['\x3F'] = "QuestionMark", - ['\x40'] = "At", - ['\x5B'] = "LeftSquareBracket", - ['\x5C'] = "Backslash", - ['\x5D'] = "RightSquareBracket", - ['\x5E'] = "Caret", - //invalidChars['\x5F'] = "Underscore"; - ['\x60'] = "Backquote", - ['\x7B'] = "LeftCurlyBrace", - ['\x7C'] = "Pipe", - ['\x7D'] = "RightCurlyBrace", - ['\x7E'] = "Tilde", - ['\x7F'] = "Delete" - }; - - return invalidChars; - } - - private static readonly Regex InvalidCharsRegex = CreateInvalidCharsRegex(); - - private static Regex CreateInvalidCharsRegex() - { - var r = string.Join("", InvalidChars.Keys.Select(c => string.Format(@"\x{0:x2}", (int)c)).ToArray()); - return new Regex("[" + r + "]", RegexOptions.Compiled); - } - - private static readonly CodeDomProvider Provider = new Microsoft.CSharp.CSharpCodeProvider(); - public static string MakeValidIdentifier(string s) - { - var id = InvalidCharsRegex.Replace(s, m => InvalidChars[m.Value[0]]); - return Provider.CreateValidIdentifier(Regex.Replace(id, @"\W+", "_")); - } - - public string ToTitleCase(string s) + private string ToTitleCase(string s) { - return ToTitleCase(s, NamingScheme); - } - - public static string ToTitleCase(string s, NamingScheme namingScheme) - { - if (string.IsNullOrEmpty(s)) { return s; } - switch (namingScheme) - { - case NamingScheme.PascalCase: - s = s.ToPascalCase(); - break; - } - return MakeValidIdentifier(s); + return s.ToTitleCase(NamingScheme); } private void BuildModel() @@ -635,7 +532,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaAnnotated type, XmlQualif { var value = new EnumValueModel { - Name = ToTitleCase(facet.Value).ToNormalizedEnumName(), + Name = _configuration.NamingProvider.EnumMemberNameFromValue(enumModel.Name, facet.Value), Value = facet.Value }; @@ -709,7 +606,7 @@ private IEnumerable CreatePropertiesForAttributes(Uri source, Typ if (attributeQualifiedName.IsEmpty || attributeQualifiedName.Namespace == "") { // inner type, have to generate a type name - var typeName = ToTitleCase(typeModel.Name) + ToTitleCase(attribute.QualifiedName.Name); + var typeName = _configuration.NamingProvider.PropertyNameFromAttribute(typeModel.Name, attribute.QualifiedName.Name); attributeQualifiedName = new XmlQualifiedName(typeName, typeModel.XmlSchemaName.Namespace); // try to avoid name clashes if (NameExists(attributeQualifiedName)) @@ -785,7 +682,7 @@ private IEnumerable CreatePropertiesForElements(Uri source, TypeM if (elementQualifiedName.IsEmpty) { // inner type, have to generate a type name - var typeName = ToTitleCase(typeModel.Name) + ToTitleCase(element.QualifiedName.Name); + var typeName = _configuration.NamingProvider.PropertyNameFromElement(typeModel.Name, element.QualifiedName.Name); elementQualifiedName = new XmlQualifiedName(typeName, typeModel.XmlSchemaName.Namespace); // try to avoid name clashes if (NameExists(elementQualifiedName)) diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index 2b9daf85..46bd5412 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -20,7 +20,7 @@ public GeneratorConfiguration() var xn = key.XmlSchemaNamespace; var name = string.Join(".", xn.Split('/').Where(p => Regex.IsMatch(p, @"^[A-Za-z]+$") && p != "schema") - .Select(n => Generator.ToTitleCase(n, NamingScheme.PascalCase))); + .Select(n => n.ToTitleCase(NamingScheme.PascalCase))); if (!string.IsNullOrEmpty(NamespacePrefix)) { name = NamespacePrefix + (string.IsNullOrEmpty(name) ? "" : ("." + name)); @@ -34,6 +34,7 @@ public GeneratorConfiguration() GenerateSerializableAttribute = GenerateDesignerCategoryAttribute = true; CollectionType = typeof(Collection<>); MemberVisitor = (member, model) => { }; + NamingProvider = new NamingProvider(NamingScheme); } /// @@ -148,5 +149,10 @@ public void WriteLog(string message) /// Optional delegate that is called for each generated type member /// public Action MemberVisitor { get; set; } + + /// + /// Provides options to customize Elementnamens with own logik + /// + public NamingProvider NamingProvider { get; set; } } } diff --git a/XmlSchemaClassGenerator/NameingExtensions.cs b/XmlSchemaClassGenerator/NameingExtensions.cs new file mode 100644 index 00000000..15833274 --- /dev/null +++ b/XmlSchemaClassGenerator/NameingExtensions.cs @@ -0,0 +1,122 @@ +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace XmlSchemaClassGenerator +{ + public static class NameingExtensions + { + private static readonly CodeDomProvider Provider = new Microsoft.CSharp.CSharpCodeProvider(); + + private static readonly Dictionary InvalidChars = new Dictionary + { + ['\x00'] = "Null", + ['\x01'] = "StartOfHeading", + ['\x02'] = "StartOfText", + ['\x03'] = "EndOfText", + ['\x04'] = "EndOfTransmission", + ['\x05'] = "Enquiry", + ['\x06'] = "Acknowledge", + ['\x07'] = "Bell", + ['\x08'] = "Backspace", + ['\x09'] = "HorizontalTab", + ['\x0A'] = "LineFeed", + ['\x0B'] = "VerticalTab", + ['\x0C'] = "FormFeed", + ['\x0D'] = "CarriageReturn", + ['\x0E'] = "ShiftOut", + ['\x0F'] = "ShiftIn", + ['\x10'] = "DataLinkEscape", + ['\x11'] = "DeviceControl1", + ['\x12'] = "DeviceControl2", + ['\x13'] = "DeviceControl3", + ['\x14'] = "DeviceControl4", + ['\x15'] = "NegativeAcknowledge", + ['\x16'] = "SynchronousIdle", + ['\x17'] = "EndOfTransmissionBlock", + ['\x18'] = "Cancel", + ['\x19'] = "EndOfMedium", + ['\x1A'] = "Substitute", + ['\x1B'] = "Escape", + ['\x1C'] = "FileSeparator", + ['\x1D'] = "GroupSeparator", + ['\x1E'] = "RecordSeparator", + ['\x1F'] = "UnitSeparator", + //invalidChars['\x20'] = "Space"; + ['\x21'] = "ExclamationMark", + ['\x22'] = "Quote", + ['\x23'] = "Hash", + ['\x24'] = "Dollar", + ['\x25'] = "Percent", + ['\x26'] = "Ampersand", + ['\x27'] = "SingleQuote", + ['\x28'] = "LeftParenthesis", + ['\x29'] = "RightParenthesis", + ['\x2A'] = "Asterisk", + ['\x2B'] = "Plus", + ['\x2C'] = "Comma", + //invalidChars['\x2D'] = "Minus"; + ['\x2E'] = "Period", + ['\x2F'] = "Slash", + ['\x3A'] = "Colon", + ['\x3B'] = "Semicolon", + ['\x3C'] = "LessThan", + ['\x3D'] = "Equal", + ['\x3E'] = "GreaterThan", + ['\x3F'] = "QuestionMark", + ['\x40'] = "At", + ['\x5B'] = "LeftSquareBracket", + ['\x5C'] = "Backslash", + ['\x5D'] = "RightSquareBracket", + ['\x5E'] = "Caret", + //invalidChars['\x5F'] = "Underscore"; + ['\x60'] = "Backquote", + ['\x7B'] = "LeftCurlyBrace", + ['\x7C'] = "Pipe", + ['\x7D'] = "RightCurlyBrace", + ['\x7E'] = "Tilde", + ['\x7F'] = "Delete" + }; + + private static readonly Regex InvalidCharsRegex = CreateInvalidCharsRegex(); + + private static Regex CreateInvalidCharsRegex() + { + var r = string.Join("", InvalidChars.Keys.Select(c => string.Format(@"\x{0:x2}", (int)c)).ToArray()); + return new Regex("[" + r + "]", RegexOptions.Compiled); + } + + public static string ToNormalizedEnumName(this string name) + { + name = name.Trim().Replace(' ', '_').Replace('\t', '_'); + if (string.IsNullOrEmpty(name)) + { + return "Item"; + } + if (!char.IsLetter(name[0])) + { + return string.Format("Item{0}", name); + } + return name; + } + + public static string ToTitleCase(this string s, NamingScheme namingScheme) + { + if (string.IsNullOrEmpty(s)) { return s; } + switch (namingScheme) + { + case NamingScheme.PascalCase: + s = s.ToPascalCase(); + break; + } + return s.MakeValidIdentifier(); + } + + private static string MakeValidIdentifier(this string s) + { + var id = InvalidCharsRegex.Replace(s, m => InvalidChars[m.Value[0]]); + return Provider.CreateValidIdentifier(Regex.Replace(id, @"\W+", "_")); + } + } +} \ No newline at end of file diff --git a/XmlSchemaClassGenerator/NamingProvider.cs b/XmlSchemaClassGenerator/NamingProvider.cs new file mode 100644 index 00000000..ca27a830 --- /dev/null +++ b/XmlSchemaClassGenerator/NamingProvider.cs @@ -0,0 +1,55 @@ +namespace XmlSchemaClassGenerator +{ + /// + /// Provides options to customize elementnamens with own logik + /// + public class NamingProvider + { + /// + /// Scheme for the naming + /// + private readonly NamingScheme _namingScheme; + + /// + /// Creates the provider + /// + /// Scheme for the naming + public NamingProvider(NamingScheme namingScheme) + { + _namingScheme = namingScheme; + } + + /// + /// Creates a name for a property of a type + /// + /// Name of the typeModel + /// Attributename in the orginal XML + /// Name of the Property + public virtual string PropertyNameFromAttribute(string typeModelName, string attributeName) + { + return PropertyNameFromElement(typeModelName, attributeName); + } + + /// + /// Creates a name for a property of a type + /// + /// Name of the typeModel + /// Elementname in the orginal XML + /// Name of the Property + public virtual string PropertyNameFromElement(string typeModelName, string elementName) + { + return typeModelName.ToTitleCase(_namingScheme) + elementName.ToTitleCase(_namingScheme); + } + + /// + /// Creates a name for an enummember based on a value + /// + /// Name of the enum + /// Value in the original XML + /// Name of the Enummember + public virtual string EnumMemberNameFromValue(string enumName, string value) + { + return value.ToTitleCase(_namingScheme).ToNormalizedEnumName(); + } + } +} \ No newline at end of file