Skip to content

Commit

Permalink
Implement a Namingprovider to override default Naminglogic
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamin.marten committed Oct 10, 2017
1 parent 2e0cc90 commit 1de6921
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 130 deletions.
2 changes: 1 addition & 1 deletion XmlSchemaClassGenerator.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand Down
14 changes: 0 additions & 14 deletions XmlSchemaClassGenerator/CodeUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
125 changes: 11 additions & 114 deletions XmlSchemaClassGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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; }
Expand Down Expand Up @@ -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<char, string> InvalidChars = CreateInvalidChars();

private static Dictionary<char, string> CreateInvalidChars()
{
var invalidChars = new Dictionary<char, string>
{
['\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()
Expand Down Expand Up @@ -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
};

Expand Down Expand Up @@ -709,7 +606,7 @@ private IEnumerable<PropertyModel> 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))
Expand Down Expand Up @@ -785,7 +682,7 @@ private IEnumerable<PropertyModel> 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))
Expand Down
8 changes: 7 additions & 1 deletion XmlSchemaClassGenerator/GeneratorConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -34,6 +34,7 @@ public GeneratorConfiguration()
GenerateSerializableAttribute = GenerateDesignerCategoryAttribute = true;
CollectionType = typeof(Collection<>);
MemberVisitor = (member, model) => { };
NamingProvider = new NamingProvider(NamingScheme);
}

/// <summary>
Expand Down Expand Up @@ -148,5 +149,10 @@ public void WriteLog(string message)
/// Optional delegate that is called for each generated type member
/// </summary>
public Action<CodeTypeMember, PropertyModel> MemberVisitor { get; set; }

/// <summary>
/// Provides options to customize Elementnamens with own logik
/// </summary>
public NamingProvider NamingProvider { get; set; }
}
}
122 changes: 122 additions & 0 deletions XmlSchemaClassGenerator/NameingExtensions.cs
Original file line number Diff line number Diff line change
@@ -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<char, string> InvalidChars = new Dictionary<char, string>
{
['\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+", "_"));
}
}
}
Loading

0 comments on commit 1de6921

Please sign in to comment.