@@ -14,16 +14,55 @@ namespace XmlSchemaClassGenerator
14
14
{
15
15
public static class CodeUtilities
16
16
{
17
- // Match non-letter followed by letter
18
- private static readonly Regex PascalCaseRegex = new ( @"[^\p{L}]\p{L}" , RegexOptions . Compiled ) ;
19
-
20
- // Uppercases first letter and all letters following non-letters.
21
- // Examples: testcase -> Testcase, html5element -> Html5Element, test_case -> Test_Case
22
- public static string ToPascalCase ( this string s ) => string . IsNullOrEmpty ( s ) ? s
23
- : char . ToUpperInvariant ( s [ 0 ] ) + PascalCaseRegex . Replace ( s . Substring ( 1 ) , m => m . Value [ 0 ] + char . ToUpperInvariant ( m . Value [ 1 ] ) . ToString ( ) ) ;
17
+ private static readonly Regex invalidCharsRgx = new Regex ( "[^_a-zA-Z0-9]" ) ;
18
+ private static readonly Regex whiteSpace = new Regex ( @"(?<=\s)" ) ;
19
+ private static readonly Regex startsWithLowerCaseChar = new Regex ( "^[a-z]" ) ;
20
+ private static readonly Regex firstCharFollowedByUpperCasesOnly = new Regex ( "(?<=[A-Z])[A-Z0-9]+$" ) ;
21
+ private static readonly Regex lowerCaseNextToNumber = new Regex ( "(?<=[0-9])[a-z]" ) ;
22
+ private static readonly Regex upperCaseInside = new Regex ( "(?<=[A-Z])[A-Z]+?((?=[A-Z][a-z])|(?=[0-9]))" ) ;
23
+
24
+ // Credits: chviLadislav
25
+ // https://stackoverflow.com/questions/18627112/how-can-i-convert-text-to-pascal-case
26
+ // Example output:
27
+ // "WARD_VS_VITAL_SIGNS" "WardVsVitalSigns"
28
+ // "Who am I?" "WhoAmI"
29
+ // "I ate before you got here" "IAteBeforeYouGotHere"
30
+ // "Hello|Who|Am|I?" "HelloWhoAmI"
31
+ // "Live long and prosper" "LiveLongAndProsper"
32
+ // "Lorem ipsum dolor..." "LoremIpsumDolor"
33
+ // "CoolSP" "CoolSp"
34
+ // "AB9CD" "Ab9Cd"
35
+ // "CCCTrigger" "CccTrigger"
36
+ // "CIRC" "Circ"
37
+ // "ID_SOME" "IdSome"
38
+ // "ID_SomeOther" "IdSomeOther"
39
+ // "ID_SOMEOther" "IdSomeOther"
40
+ // "CCC_SOME_2Phases" "CccSome2Phases"
41
+ // "AlreadyGoodPascalCase" "AlreadyGoodPascalCase"
42
+ // "999 999 99 9 " "999999999"
43
+ // "1 2 3 " "123"
44
+ // "1 AB cd EFDDD 8" "1AbCdEfddd8"
45
+ // "INVALID VALUE AND _2THINGS" "InvalidValueAnd2Things"
46
+ public static string ToPascalCase ( this string original )
47
+ {
48
+ // replace white spaces with undescore, then replace all invalid chars with empty string
49
+ var pascalCase = invalidCharsRgx . Replace ( whiteSpace . Replace ( original , "_" ) , string . Empty )
50
+ // split by underscores
51
+ . Split ( new char [ ] { '_' } , StringSplitOptions . RemoveEmptyEntries )
52
+ // set first letter to uppercase
53
+ . Select ( w => startsWithLowerCaseChar . Replace ( w , m => m . Value . ToUpper ( ) ) )
54
+ // replace second and all following upper case letters to lower if there is no next lower (ABC -> Abc)
55
+ . Select ( w => firstCharFollowedByUpperCasesOnly . Replace ( w , m => m . Value . ToLower ( ) ) )
56
+ // set upper case the first lower case following a number (Ab9cd -> Ab9Cd)
57
+ . Select ( w => lowerCaseNextToNumber . Replace ( w , m => m . Value . ToUpper ( ) ) )
58
+ // lower second and next upper case letters except the last if it follows by any lower (ABcDEf -> AbcDef)
59
+ . Select ( w => upperCaseInside . Replace ( w , m => m . Value . ToLower ( ) ) ) ;
60
+
61
+ return string . Concat ( pascalCase ) ;
62
+ }
24
63
25
64
public static string ToCamelCase ( this string s ) => string . IsNullOrEmpty ( s ) ? s
26
- : char . ToLowerInvariant ( s [ 0 ] ) + s . Substring ( 1 ) ;
65
+ : char . ToLowerInvariant ( s [ 0 ] ) + s . Substring ( 1 ) ;
27
66
28
67
public static string ToBackingField ( this string propertyName , string privateFieldPrefix )
29
68
=> string . Concat ( privateFieldPrefix , propertyName . ToCamelCase ( ) ) ;
@@ -76,37 +115,37 @@ private static Type GetIntegerDerivedType(XmlSchemaDatatype xml, GeneratorConfig
76
115
Type FromDigitRestriction ( TotalDigitsRestrictionModel totalDigits
77
116
) => xml . TypeCode switch
78
117
{
79
- XmlTypeCode . PositiveInteger or XmlTypeCode . NonNegativeInteger => totalDigits ? . Value switch
80
- {
81
- < 3 => typeof ( byte ) ,
82
- < 5 => typeof ( ushort ) ,
83
- < 10 => typeof ( uint ) ,
84
- < 20 => typeof ( ulong ) ,
85
- < 30 => typeof ( decimal ) ,
86
- _ => null
87
- } ,
88
- XmlTypeCode . Integer or XmlTypeCode . NegativeInteger or XmlTypeCode . NonPositiveInteger => totalDigits
89
- ? . Value switch
90
- {
91
- < 3 => typeof ( sbyte ) ,
92
- < 5 => typeof ( short ) ,
93
- < 10 => typeof ( int ) ,
94
- < 19 => typeof ( long ) ,
95
- < 29 => typeof ( decimal ) ,
96
- _ => null
97
- } ,
98
- XmlTypeCode . Decimal
99
- when restrictions . OfType < FractionDigitsRestrictionModel > ( ) . SingleOrDefault ( ) is { IsSupported : true , Value : 0 } => totalDigits
100
- ? . Value switch
101
- {
102
- < 3 => typeof ( sbyte ) ,
103
- < 5 => typeof ( short ) ,
104
- < 10 => typeof ( int ) ,
105
- < 19 => typeof ( long ) ,
106
- < 29 => typeof ( decimal ) ,
107
- _ => null
108
- } ,
109
- _ => null
118
+ XmlTypeCode . PositiveInteger or XmlTypeCode . NonNegativeInteger => totalDigits ? . Value switch
119
+ {
120
+ < 3 => typeof ( byte ) ,
121
+ < 5 => typeof ( ushort ) ,
122
+ < 10 => typeof ( uint ) ,
123
+ < 20 => typeof ( ulong ) ,
124
+ < 30 => typeof ( decimal ) ,
125
+ _ => null
126
+ } ,
127
+ XmlTypeCode . Integer or XmlTypeCode . NegativeInteger or XmlTypeCode . NonPositiveInteger => totalDigits
128
+ ? . Value switch
129
+ {
130
+ < 3 => typeof ( sbyte ) ,
131
+ < 5 => typeof ( short ) ,
132
+ < 10 => typeof ( int ) ,
133
+ < 19 => typeof ( long ) ,
134
+ < 29 => typeof ( decimal ) ,
135
+ _ => null
136
+ } ,
137
+ XmlTypeCode . Decimal
138
+ when restrictions . OfType < FractionDigitsRestrictionModel > ( ) . SingleOrDefault ( ) is { IsSupported : true , Value : 0 } => totalDigits
139
+ ? . Value switch
140
+ {
141
+ < 3 => typeof ( sbyte ) ,
142
+ < 5 => typeof ( short ) ,
143
+ < 10 => typeof ( int ) ,
144
+ < 19 => typeof ( long ) ,
145
+ < 29 => typeof ( decimal ) ,
146
+ _ => null
147
+ } ,
148
+ _ => null
110
149
} ;
111
150
112
151
Type FromFallback ( ) => configuration . UseIntegerDataTypeAsFallback && configuration . IntegerDataType != null ? configuration . IntegerDataType : typeof ( string ) ;
@@ -124,8 +163,8 @@ public static Type GetEffectiveType(this XmlSchemaDatatype type, GeneratorConfig
124
163
XmlTypeCode . Time => typeof ( DateTime ) ,
125
164
XmlTypeCode . Idref => typeof ( string ) ,
126
165
XmlTypeCode . Integer or XmlTypeCode . NegativeInteger or XmlTypeCode . NonNegativeInteger or XmlTypeCode . NonPositiveInteger or XmlTypeCode . PositiveInteger => GetIntegerDerivedType ( type , configuration , restrictions ) ,
127
- XmlTypeCode . Decimal when restrictions . OfType < FractionDigitsRestrictionModel > ( ) . SingleOrDefault ( ) is { IsSupported : true , Value : 0 } => GetIntegerDerivedType ( type , configuration , restrictions ) ,
128
- _ => type . ValueType ,
166
+ XmlTypeCode . Decimal when restrictions . OfType < FractionDigitsRestrictionModel > ( ) . SingleOrDefault ( ) is { IsSupported : true , Value : 0 } => GetIntegerDerivedType ( type , configuration , restrictions ) ,
167
+ _ => type . ValueType ,
129
168
} ;
130
169
131
170
if ( schemaType . IsDerivedFrom ( GuidQualifiedName ) )
0 commit comments