Skip to content

Commit 0343da0

Browse files
author
Michael Ganss
committed
Support MinLength and MaxLength for PCL as well through StringLengthAttribute
1 parent e44ebbd commit 0343da0

File tree

4 files changed

+98
-53
lines changed

4 files changed

+98
-53
lines changed

XmlSchemaClassGenerator.Tests/XmlTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private Assembly Compile(string name, string pattern)
4343
Log = f => cs.Add(f),
4444
GenerateNullables = true,
4545
IntegerDataType = typeof(int),
46-
DataAnnotationMode = DataAnnotationMode.None,
46+
DataAnnotationMode = DataAnnotationMode.Partial,
4747
GenerateDesignerCategoryAttribute = false,
4848
};
4949

@@ -60,6 +60,7 @@ private Assembly Compile(string name, string pattern)
6060
"System.Xml.Linq.dll",
6161
"System.Xml.Serialization.dll",
6262
"System.ServiceModel.dll",
63+
"System.ComponentModel.DataAnnotations.dll",
6364
};
6465

6566
var binFolder = Path.Combine(outputFolder, "bin");

XmlSchemaClassGenerator/Generator.cs

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaType type, XmlQualifiedNa
662662
return enumModel;
663663
}
664664

665-
restrictions = typeRestriction.Facets.Cast<XmlSchemaFacet>().Select(f => GetRestriction(simpleType, f)).Where(r => r != null).Sanitize().ToList();
665+
restrictions = GetRestrictions(typeRestriction.Facets.Cast<XmlSchemaFacet>(), simpleType).Where(r => r != null).Sanitize().ToList();
666666
}
667667

668668
var simpleModelName = ToTitleCase(qualifiedName.Name);
@@ -716,33 +716,40 @@ private bool NameExists(XmlQualifiedName name)
716716
return elements.Concat(types).Any(n => n.Namespace == name.Namespace && name.Name.Equals(n.Name, StringComparison.OrdinalIgnoreCase));
717717
}
718718

719-
private RestrictionModel GetRestriction(XmlSchemaSimpleType type, XmlSchemaFacet facet)
719+
private IEnumerable<RestrictionModel> GetRestrictions(IEnumerable<XmlSchemaFacet> facets, XmlSchemaSimpleType type)
720720
{
721-
if (facet is XmlSchemaMaxLengthFacet)
722-
return new MaxLengthRestrictionModel(_configuration) { Value = int.Parse(facet.Value) };
723-
if (facet is XmlSchemaMinLengthFacet)
724-
return new MinLengthRestrictionModel(_configuration) { Value = int.Parse(facet.Value) };
725-
if (facet is XmlSchemaTotalDigitsFacet)
726-
return new TotalDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) };
727-
if (facet is XmlSchemaFractionDigitsFacet)
728-
return new FractionDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) };
729-
730-
if (facet is XmlSchemaPatternFacet)
731-
return new PatternRestrictionModel(_configuration) { Value = facet.Value };
732-
733-
var valueType = type.Datatype.ValueType;
734-
735-
if (facet is XmlSchemaMinInclusiveFacet)
736-
return new MinInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
737-
if (facet is XmlSchemaMinExclusiveFacet)
738-
return new MinExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
739-
if (facet is XmlSchemaMaxInclusiveFacet)
740-
return new MaxInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
741-
if (facet is XmlSchemaMaxExclusiveFacet)
742-
return new MaxExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
743-
744-
// unsupported restriction
745-
return null;
721+
var min = facets.OfType<XmlSchemaMinLengthFacet>().Select(f => int.Parse(f.Value)).DefaultIfEmpty().Max();
722+
var max = facets.OfType<XmlSchemaMaxLengthFacet>().Select(f => int.Parse(f.Value)).DefaultIfEmpty().Min();
723+
724+
if (DataAnnotationMode == XmlSchemaClassGenerator.DataAnnotationMode.All)
725+
{
726+
if (min > 0) yield return new MinLengthRestrictionModel(_configuration) { Value = min };
727+
if (max > 0) yield return new MaxLengthRestrictionModel(_configuration) { Value = max };
728+
}
729+
else if (min > 0 || max > 0)
730+
yield return new MinMaxLengthRestrictionModel(_configuration) { Min = min, Max = max };
731+
732+
foreach (var facet in facets)
733+
{
734+
if (facet is XmlSchemaTotalDigitsFacet)
735+
yield return new TotalDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) };
736+
if (facet is XmlSchemaFractionDigitsFacet)
737+
yield return new FractionDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) };
738+
739+
if (facet is XmlSchemaPatternFacet)
740+
yield return new PatternRestrictionModel(_configuration) { Value = facet.Value };
741+
742+
var valueType = type.Datatype.ValueType;
743+
744+
if (facet is XmlSchemaMinInclusiveFacet)
745+
yield return new MinInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
746+
if (facet is XmlSchemaMinExclusiveFacet)
747+
yield return new MinExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
748+
if (facet is XmlSchemaMaxInclusiveFacet)
749+
yield return new MaxInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
750+
if (facet is XmlSchemaMaxExclusiveFacet)
751+
yield return new MaxExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType };
752+
}
746753
}
747754

748755
public IEnumerable<Particle> GetElements(XmlSchemaGroupBase groupBase)

XmlSchemaClassGenerator/RestrictionModel.cs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public abstract class ValueRestrictionModel<T> : RestrictionModel
3838
protected ValueRestrictionModel(GeneratorConfiguration configuration)
3939
: base(configuration)
4040
{
41-
41+
4242
}
4343

4444
public T Value { get; set; }
@@ -54,18 +54,55 @@ public abstract class ValueTypeRestrictionModel: ValueRestrictionModel<string>
5454
protected ValueTypeRestrictionModel(GeneratorConfiguration configuration)
5555
: base(configuration)
5656
{
57-
57+
5858
}
5959

6060
public Type Type { get; set; }
6161
}
6262

63+
public class MinMaxLengthRestrictionModel : RestrictionModel
64+
{
65+
public MinMaxLengthRestrictionModel(GeneratorConfiguration configuration)
66+
: base(configuration)
67+
{
68+
69+
}
70+
71+
public int Min { get; set; }
72+
public int Max { get; set; }
73+
74+
public override string Description
75+
{
76+
get
77+
{
78+
var s = "";
79+
if (Min > 0) s += string.Format("Minimum length: {0}. ", Min);
80+
if (Max > 0) s += string.Format("Maximum length: {0}.", Max);
81+
return s.Trim();
82+
}
83+
}
84+
85+
public override DataAnnotationMode MinimumDataAnnotationMode
86+
{
87+
get { return DataAnnotationMode.Partial; }
88+
}
89+
90+
public override CodeAttributeDeclaration GetAttribute()
91+
{
92+
var a = new CodeAttributeDeclaration(new CodeTypeReference(typeof(StringLengthAttribute)),
93+
new CodeAttributeArgument(Max > 0 ? (CodeExpression)new CodePrimitiveExpression(Max) : new CodeSnippetExpression("int.MaxValue")));
94+
if (Min > 0) a.Arguments.Add(new CodeAttributeArgument("MinimumLength", new CodePrimitiveExpression(Min)));
95+
96+
return a;
97+
}
98+
}
99+
63100
public class MaxLengthRestrictionModel : ValueRestrictionModel<int>
64101
{
65102
public MaxLengthRestrictionModel(GeneratorConfiguration configuration)
66103
: base(configuration)
67104
{
68-
105+
69106
}
70107

71108
public override string Description

XmlSchemaClassGenerator/TypeModel.cs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ public static IEnumerable<CodeCommentStatement> GetComments(IEnumerable<Document
7272

7373
foreach (var doc in docs.OrderBy(d => d.Language))
7474
{
75-
var comment = string.Format(@"<para{0}>{1}</para>",
76-
string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language),
75+
var comment = string.Format(@"<para{0}>{1}</para>",
76+
string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language),
7777
Regex.Replace(doc.Text, @"(^|[^\r])\n", "$1\r\n")); // normalize newlines
7878
yield return new CodeCommentStatement(comment, true);
7979
}
@@ -362,51 +362,51 @@ internal static string GetAccessors(string memberName, string backingFieldName,
362362
switch (typeCode)
363363
{
364364
case PropertyValueTypeCode.ValueType:
365-
return string.Format(@"
365+
return string.Format(@"
366366
{{
367-
get
367+
get
368368
{{
369369
return {0};
370370
}}
371-
{2}set
371+
{2}set
372372
{{
373-
if (!{0}.Equals(value))
373+
if (!{0}.Equals(value))
374374
{{
375375
{0} = value;
376376
OnPropertyChanged(""{1}"");
377377
}}
378378
}}
379379
}}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty));
380380
case PropertyValueTypeCode.Other:
381-
return string.Format(@"
381+
return string.Format(@"
382382
{{
383-
get
383+
get
384384
{{
385385
return {0};
386386
}}
387-
{2}set
387+
{2}set
388388
{{
389389
if ({0} == value)
390390
return;
391-
if ({0} == null || value == null || !{0}.Equals(value))
391+
if ({0} == null || value == null || !{0}.Equals(value))
392392
{{
393393
{0} = value;
394394
OnPropertyChanged(""{1}"");
395395
}}
396396
}}
397397
}}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty));
398398
case PropertyValueTypeCode.Array:
399-
return string.Format(@"
399+
return string.Format(@"
400400
{{
401-
get
401+
get
402402
{{
403403
return {0};
404404
}}
405-
{2}set
405+
{2}set
406406
{{
407407
if ({0} == value)
408408
return;
409-
if ({0} == null || value == null || !{0}.SequenceEqual(value))
409+
if ({0} == null || value == null || !{0}.SequenceEqual(value))
410410
{{
411411
{0} = value;
412412
OnPropertyChanged(""{1}"");
@@ -415,13 +415,13 @@ internal static string GetAccessors(string memberName, string backingFieldName,
415415
}}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty));
416416
}
417417
}
418-
return string.Format(@"
418+
return string.Format(@"
419419
{{
420-
get
420+
get
421421
{{
422422
return this.{0};
423423
}}
424-
{1}set
424+
{1}set
425425
{{
426426
this.{0} = value;
427427
}}
@@ -438,8 +438,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
438438
&& !typeClassModel.Properties[0].IsAttribute && !typeClassModel.Properties[0].IsAny
439439
&& typeClassModel.BaseClass == null;
440440
var propertyType = !isArray ? Type : typeClassModel.Properties[0].Type;
441-
var isNullableValueType = DefaultValue == null
442-
&& IsNullable && !(IsCollection || isArray)
441+
var isNullableValueType = DefaultValue == null
442+
&& IsNullable && !(IsCollection || isArray)
443443
&& ((propertyType is EnumModel) || (propertyType is SimpleModel && ((SimpleModel)propertyType).ValueType.IsValueType));
444444

445445
var typeReference = propertyType.GetReferenceFor(OwningType.Namespace, IsCollection || isArray);
@@ -530,8 +530,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
530530
// public X? Name
531531
// {
532532
// get { return NameSpecified ? NameValue : null; }
533-
// set
534-
// {
533+
// set
534+
// {
535535
// NameValue = value.GetValueOrDefault();
536536
// NameSpecified = value.HasValue;
537537
// }
@@ -765,7 +765,7 @@ public override CodeTypeDeclaration Generate()
765765
// From .NET 3.5 XmlSerializer doesn't serialize objects with [Obsolete] >(
766766
//var deprecatedAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(ObsoleteAttribute)));
767767
//member.CustomAttributes.Add(deprecatedAttribute);
768-
768+
769769
var obsolete = new DocumentationModel { Language = "en", Text = "[Obsolete]" };
770770
docs.Add(obsolete);
771771
}

0 commit comments

Comments
 (0)