From 0343da0d6af519842e1071ea258123692d584fce Mon Sep 17 00:00:00 2001 From: Michael Ganss Date: Mon, 2 Mar 2015 19:13:16 +0100 Subject: [PATCH] Support MinLength and MaxLength for PCL as well through StringLengthAttribute --- XmlSchemaClassGenerator.Tests/XmlTests.cs | 3 +- XmlSchemaClassGenerator/Generator.cs | 61 ++++++++++++--------- XmlSchemaClassGenerator/RestrictionModel.cs | 43 ++++++++++++++- XmlSchemaClassGenerator/TypeModel.cs | 44 +++++++-------- 4 files changed, 98 insertions(+), 53 deletions(-) diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 739c4ce5..09bffb02 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -43,7 +43,7 @@ private Assembly Compile(string name, string pattern) Log = f => cs.Add(f), GenerateNullables = true, IntegerDataType = typeof(int), - DataAnnotationMode = DataAnnotationMode.None, + DataAnnotationMode = DataAnnotationMode.Partial, GenerateDesignerCategoryAttribute = false, }; @@ -60,6 +60,7 @@ private Assembly Compile(string name, string pattern) "System.Xml.Linq.dll", "System.Xml.Serialization.dll", "System.ServiceModel.dll", + "System.ComponentModel.DataAnnotations.dll", }; var binFolder = Path.Combine(outputFolder, "bin"); diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index b0f8a6e2..bbbf0e0b 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -662,7 +662,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaType type, XmlQualifiedNa return enumModel; } - restrictions = typeRestriction.Facets.Cast().Select(f => GetRestriction(simpleType, f)).Where(r => r != null).Sanitize().ToList(); + restrictions = GetRestrictions(typeRestriction.Facets.Cast(), simpleType).Where(r => r != null).Sanitize().ToList(); } var simpleModelName = ToTitleCase(qualifiedName.Name); @@ -716,33 +716,40 @@ private bool NameExists(XmlQualifiedName name) return elements.Concat(types).Any(n => n.Namespace == name.Namespace && name.Name.Equals(n.Name, StringComparison.OrdinalIgnoreCase)); } - private RestrictionModel GetRestriction(XmlSchemaSimpleType type, XmlSchemaFacet facet) + private IEnumerable GetRestrictions(IEnumerable facets, XmlSchemaSimpleType type) { - if (facet is XmlSchemaMaxLengthFacet) - return new MaxLengthRestrictionModel(_configuration) { Value = int.Parse(facet.Value) }; - if (facet is XmlSchemaMinLengthFacet) - return new MinLengthRestrictionModel(_configuration) { Value = int.Parse(facet.Value) }; - if (facet is XmlSchemaTotalDigitsFacet) - return new TotalDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) }; - if (facet is XmlSchemaFractionDigitsFacet) - return new FractionDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) }; - - if (facet is XmlSchemaPatternFacet) - return new PatternRestrictionModel(_configuration) { Value = facet.Value }; - - var valueType = type.Datatype.ValueType; - - if (facet is XmlSchemaMinInclusiveFacet) - return new MinInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; - if (facet is XmlSchemaMinExclusiveFacet) - return new MinExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; - if (facet is XmlSchemaMaxInclusiveFacet) - return new MaxInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; - if (facet is XmlSchemaMaxExclusiveFacet) - return new MaxExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; - - // unsupported restriction - return null; + var min = facets.OfType().Select(f => int.Parse(f.Value)).DefaultIfEmpty().Max(); + var max = facets.OfType().Select(f => int.Parse(f.Value)).DefaultIfEmpty().Min(); + + if (DataAnnotationMode == XmlSchemaClassGenerator.DataAnnotationMode.All) + { + if (min > 0) yield return new MinLengthRestrictionModel(_configuration) { Value = min }; + if (max > 0) yield return new MaxLengthRestrictionModel(_configuration) { Value = max }; + } + else if (min > 0 || max > 0) + yield return new MinMaxLengthRestrictionModel(_configuration) { Min = min, Max = max }; + + foreach (var facet in facets) + { + if (facet is XmlSchemaTotalDigitsFacet) + yield return new TotalDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) }; + if (facet is XmlSchemaFractionDigitsFacet) + yield return new FractionDigitsRestrictionModel(_configuration) { Value = int.Parse(facet.Value) }; + + if (facet is XmlSchemaPatternFacet) + yield return new PatternRestrictionModel(_configuration) { Value = facet.Value }; + + var valueType = type.Datatype.ValueType; + + if (facet is XmlSchemaMinInclusiveFacet) + yield return new MinInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; + if (facet is XmlSchemaMinExclusiveFacet) + yield return new MinExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; + if (facet is XmlSchemaMaxInclusiveFacet) + yield return new MaxInclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; + if (facet is XmlSchemaMaxExclusiveFacet) + yield return new MaxExclusiveRestrictionModel(_configuration) { Value = facet.Value, Type = valueType }; + } } public IEnumerable GetElements(XmlSchemaGroupBase groupBase) diff --git a/XmlSchemaClassGenerator/RestrictionModel.cs b/XmlSchemaClassGenerator/RestrictionModel.cs index ffef1f6e..d643e07f 100644 --- a/XmlSchemaClassGenerator/RestrictionModel.cs +++ b/XmlSchemaClassGenerator/RestrictionModel.cs @@ -38,7 +38,7 @@ public abstract class ValueRestrictionModel : RestrictionModel protected ValueRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { - + } public T Value { get; set; } @@ -54,18 +54,55 @@ public abstract class ValueTypeRestrictionModel: ValueRestrictionModel protected ValueTypeRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { - + } public Type Type { get; set; } } + public class MinMaxLengthRestrictionModel : RestrictionModel + { + public MinMaxLengthRestrictionModel(GeneratorConfiguration configuration) + : base(configuration) + { + + } + + public int Min { get; set; } + public int Max { get; set; } + + public override string Description + { + get + { + var s = ""; + if (Min > 0) s += string.Format("Minimum length: {0}. ", Min); + if (Max > 0) s += string.Format("Maximum length: {0}.", Max); + return s.Trim(); + } + } + + public override DataAnnotationMode MinimumDataAnnotationMode + { + get { return DataAnnotationMode.Partial; } + } + + public override CodeAttributeDeclaration GetAttribute() + { + var a = new CodeAttributeDeclaration(new CodeTypeReference(typeof(StringLengthAttribute)), + new CodeAttributeArgument(Max > 0 ? (CodeExpression)new CodePrimitiveExpression(Max) : new CodeSnippetExpression("int.MaxValue"))); + if (Min > 0) a.Arguments.Add(new CodeAttributeArgument("MinimumLength", new CodePrimitiveExpression(Min))); + + return a; + } + } + public class MaxLengthRestrictionModel : ValueRestrictionModel { public MaxLengthRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { - + } public override string Description diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index 55e7bb9e..f744a51e 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -72,8 +72,8 @@ public static IEnumerable GetComments(IEnumerable d.Language)) { - var comment = string.Format(@"{1}", - string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language), + var comment = string.Format(@"{1}", + string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language), Regex.Replace(doc.Text, @"(^|[^\r])\n", "$1\r\n")); // normalize newlines yield return new CodeCommentStatement(comment, true); } @@ -362,15 +362,15 @@ internal static string GetAccessors(string memberName, string backingFieldName, switch (typeCode) { case PropertyValueTypeCode.ValueType: - return string.Format(@" + return string.Format(@" {{ - get + get {{ return {0}; }} - {2}set + {2}set {{ - if (!{0}.Equals(value)) + if (!{0}.Equals(value)) {{ {0} = value; OnPropertyChanged(""{1}""); @@ -378,17 +378,17 @@ internal static string GetAccessors(string memberName, string backingFieldName, }} }}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty)); case PropertyValueTypeCode.Other: - return string.Format(@" + return string.Format(@" {{ - get + get {{ return {0}; }} - {2}set + {2}set {{ if ({0} == value) return; - if ({0} == null || value == null || !{0}.Equals(value)) + if ({0} == null || value == null || !{0}.Equals(value)) {{ {0} = value; OnPropertyChanged(""{1}""); @@ -396,17 +396,17 @@ internal static string GetAccessors(string memberName, string backingFieldName, }} }}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty)); case PropertyValueTypeCode.Array: - return string.Format(@" + return string.Format(@" {{ - get + get {{ return {0}; }} - {2}set + {2}set {{ if ({0} == value) return; - if ({0} == null || value == null || !{0}.SequenceEqual(value)) + if ({0} == null || value == null || !{0}.SequenceEqual(value)) {{ {0} = value; OnPropertyChanged(""{1}""); @@ -415,13 +415,13 @@ internal static string GetAccessors(string memberName, string backingFieldName, }}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty)); } } - return string.Format(@" + return string.Format(@" {{ - get + get {{ return this.{0}; }} - {1}set + {1}set {{ this.{0} = value; }} @@ -438,8 +438,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi && !typeClassModel.Properties[0].IsAttribute && !typeClassModel.Properties[0].IsAny && typeClassModel.BaseClass == null; var propertyType = !isArray ? Type : typeClassModel.Properties[0].Type; - var isNullableValueType = DefaultValue == null - && IsNullable && !(IsCollection || isArray) + var isNullableValueType = DefaultValue == null + && IsNullable && !(IsCollection || isArray) && ((propertyType is EnumModel) || (propertyType is SimpleModel && ((SimpleModel)propertyType).ValueType.IsValueType)); var typeReference = propertyType.GetReferenceFor(OwningType.Namespace, IsCollection || isArray); @@ -530,8 +530,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi // public X? Name // { // get { return NameSpecified ? NameValue : null; } - // set - // { + // set + // { // NameValue = value.GetValueOrDefault(); // NameSpecified = value.HasValue; // } @@ -765,7 +765,7 @@ public override CodeTypeDeclaration Generate() // From .NET 3.5 XmlSerializer doesn't serialize objects with [Obsolete] >( //var deprecatedAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(ObsoleteAttribute))); //member.CustomAttributes.Add(deprecatedAttribute); - + var obsolete = new DocumentationModel { Language = "en", Text = "[Obsolete]" }; docs.Add(obsolete); }