Skip to content

Commit

Permalink
Support MinLength and MaxLength for PCL as well through StringLengthA…
Browse files Browse the repository at this point in the history
…ttribute
  • Loading branch information
Michael Ganss committed Mar 2, 2015
1 parent e44ebbd commit 0343da0
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 53 deletions.
3 changes: 2 additions & 1 deletion XmlSchemaClassGenerator.Tests/XmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -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");
Expand Down
61 changes: 34 additions & 27 deletions XmlSchemaClassGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaType type, XmlQualifiedNa
return enumModel;
}

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

var simpleModelName = ToTitleCase(qualifiedName.Name);
Expand Down Expand Up @@ -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<RestrictionModel> GetRestrictions(IEnumerable<XmlSchemaFacet> 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<XmlSchemaMinLengthFacet>().Select(f => int.Parse(f.Value)).DefaultIfEmpty().Max();
var max = facets.OfType<XmlSchemaMaxLengthFacet>().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<Particle> GetElements(XmlSchemaGroupBase groupBase)
Expand Down
43 changes: 40 additions & 3 deletions XmlSchemaClassGenerator/RestrictionModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public abstract class ValueRestrictionModel<T> : RestrictionModel
protected ValueRestrictionModel(GeneratorConfiguration configuration)
: base(configuration)
{

}

public T Value { get; set; }
Expand All @@ -54,18 +54,55 @@ public abstract class ValueTypeRestrictionModel: ValueRestrictionModel<string>
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<int>
{
public MaxLengthRestrictionModel(GeneratorConfiguration configuration)
: base(configuration)
{

}

public override string Description
Expand Down
44 changes: 22 additions & 22 deletions XmlSchemaClassGenerator/TypeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public static IEnumerable<CodeCommentStatement> GetComments(IEnumerable<Document

foreach (var doc in docs.OrderBy(d => d.Language))
{
var comment = string.Format(@"<para{0}>{1}</para>",
string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language),
var comment = string.Format(@"<para{0}>{1}</para>",
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);
}
Expand Down Expand Up @@ -362,51 +362,51 @@ 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}"");
}}
}}
}}", 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}"");
}}
}}
}}", 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}"");
Expand All @@ -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;
}}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
// }
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 0343da0

Please sign in to comment.