Skip to content

Commit

Permalink
Merge pull request #201 from AVTit/allow-omit-isnullable
Browse files Browse the repository at this point in the history
Support for omitting IsNullable=true generation for nullable elements
  • Loading branch information
mganss authored May 14, 2020
2 parents ac035ab + 4b4c95e commit 21bedfd
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 5 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ Options:
pattern (default is false)
--sf, --separateFiles generate a separate file for each class (default
is false)
--dnfin, --doNotForceIsNullable
do not force generator to emit IsNullable = true
in XmlElement annotation for nillable elements
when element is nullable (minOccurs < 1 or
parent element is choice) (default is false)
```

For use from code use the [library NuGet package](https://www.nuget.org/packages/XmlSchemaClassGenerator-beta/):
Expand Down
5 changes: 4 additions & 1 deletion XmlSchemaClassGenerator.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static void Main(string[] args)
var useShouldSerialize = false;
var separateClasses = false;
var collectionSettersMode = CollectionSettersMode.Private;
var doNotForceIsNullable = false;

var options = new OptionSet {
{ "h|help", "show this message and exit", v => showHelp = v != null },
Expand Down Expand Up @@ -120,6 +121,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l
{ "cc|complexTypesForCollections", "generate complex types for collections (default is true)", v => generateComplexTypesForCollections = v != null },
{ "s|useShouldSerialize", "use ShouldSerialize pattern instead of Specified pattern (default is false)", v => useShouldSerialize = v != null },
{ "sf|separateFiles", "generate a separate file for each class (default is false)", v => separateClasses = v != null },
{ "dnfin|doNotForceIsNullable", "do not force generator to emit IsNullable = true in XmlElement annotation for nillable elements when element is nullable (minOccurs < 1 or parent element is choice) (default is false)", v => doNotForceIsNullable = v != null }
};

var globsAndUris = options.Parse(args);
Expand Down Expand Up @@ -188,7 +190,8 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l
GenerateComplexTypesForCollections = generateComplexTypesForCollections,
UseShouldSerializePattern = useShouldSerialize,
SeparateClasses = separateClasses,
CollectionSettersMode = collectionSettersMode
CollectionSettersMode = collectionSettersMode,
DoNotForceIsNullable = doNotForceIsNullable
};

if (pclCompatible)
Expand Down
106 changes: 103 additions & 3 deletions XmlSchemaClassGenerator.Tests/XmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ private IEnumerable<string> ConvertXml(string name, IEnumerable<string> xsds, Ge
AssemblyVisible = generatorPrototype.AssemblyVisible,
GenerateInterfaces = generatorPrototype.GenerateInterfaces,
MemberVisitor = generatorPrototype.MemberVisitor,
CodeTypeReferenceOptions = generatorPrototype.CodeTypeReferenceOptions
CodeTypeReferenceOptions = generatorPrototype.CodeTypeReferenceOptions,
DoNotForceIsNullable = generatorPrototype.DoNotForceIsNullable
};

var set = new XmlSchemaSet();
Expand Down Expand Up @@ -1941,11 +1942,110 @@ public void TestShouldPatternForCollections()
};

var contents = ConvertXml(nameof(TestShouldPatternForCollections), xsd, generator).ToArray();
Assert.Equal(1, contents.Length);
var assembly = Compiler.Compile(nameof(GenerateXmlRootAttributeForEnumTest), contents);
Assert.Single(contents);
var assembly = Compiler.Compile(nameof(TestShouldPatternForCollections), contents);
var testType = assembly.GetType("Test_NS1.TestType");
var serializer = new XmlSerializer(testType);
Assert.NotNull(serializer);
}


[Fact]
public void TestDoNotForceIsNullableGeneration()
{
const string xsd = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" targetNamespace=""Test_NS1""
elementFormDefault=""qualified"" attributeFormDefault=""unqualified"">
<xs:element name=""TestType"">
<xs:complexType>
<xs:sequence>
<xs:element name=""StringProperty"" type=""xs:string"" nillable=""true"" minOccurs=""0""/>
<xs:element name=""StringNullableProperty"" type=""xs:string"" nillable=""true""/>
<xs:element name=""StringNullableProperty2"" type=""xs:string"" nillable=""true"" minOccurs=""1""/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>";

var generator = new Generator
{
NamespaceProvider = new NamespaceProvider
{
GenerateNamespace = key => key.XmlSchemaNamespace
},
DoNotForceIsNullable = true
};

var contents = ConvertXml(nameof(TestDoNotForceIsNullableGeneration), xsd, generator).ToArray();
Assert.Single(contents);
var assembly = Compiler.Compile(nameof(TestDoNotForceIsNullableGeneration), contents);
var testType = assembly.GetType("Test_NS1.TestType");
var serializer = new XmlSerializer(testType);
Assert.NotNull(serializer);

var prop = testType.GetProperty("StringProperty");
Assert.NotNull(prop);
var xmlElementAttribute = prop.GetCustomAttribute<XmlElementAttribute>();
Assert.False(xmlElementAttribute.IsNullable);

prop = testType.GetProperty("StringNullableProperty");
Assert.NotNull(prop);
var xmlElementNullableAttribute = prop.GetCustomAttribute<XmlElementAttribute>();
Assert.True(xmlElementNullableAttribute.IsNullable);

prop = testType.GetProperty("StringNullableProperty2");
Assert.NotNull(prop);
var xmlElementNullableAttribute2 = prop.GetCustomAttribute<XmlElementAttribute>();
Assert.True(xmlElementNullableAttribute2.IsNullable);
}

[Fact]
public void TestForceIsNullableGeneration()
{
const string xsd = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" targetNamespace=""Test_NS1""
elementFormDefault=""qualified"" attributeFormDefault=""unqualified"">
<xs:element name=""TestType"">
<xs:complexType>
<xs:sequence>
<xs:element name=""StringProperty"" type=""xs:string"" nillable=""true"" minOccurs=""0""/>
<xs:element name=""StringNullableProperty"" type=""xs:string"" nillable=""true""/>
<xs:element name=""StringNullableProperty2"" type=""xs:string"" nillable=""true"" minOccurs=""1""/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>";

var generator = new Generator
{
NamespaceProvider = new NamespaceProvider
{
GenerateNamespace = key => key.XmlSchemaNamespace
},
DoNotForceIsNullable = false
};

var contents = ConvertXml(nameof(TestForceIsNullableGeneration), xsd, generator).ToArray();
Assert.Single(contents);
var assembly = Compiler.Compile(nameof(TestForceIsNullableGeneration), contents);
var testType = assembly.GetType("Test_NS1.TestType");
var serializer = new XmlSerializer(testType);
Assert.NotNull(serializer);

var prop = testType.GetProperty("StringProperty");
Assert.NotNull(prop);
var xmlElementAttribute = prop.GetCustomAttribute<XmlElementAttribute>();
Assert.True(xmlElementAttribute.IsNullable);

prop = testType.GetProperty("StringNullableProperty");
Assert.NotNull(prop);
var xmlElementNullableAttribute = prop.GetCustomAttribute<XmlElementAttribute>();
Assert.True(xmlElementNullableAttribute.IsNullable);

prop = testType.GetProperty("StringNullableProperty2");
Assert.NotNull(prop);
var xmlElementNullableAttribute2 = prop.GetCustomAttribute<XmlElementAttribute>();
Assert.True(xmlElementNullableAttribute2.IsNullable);
}
}
}
6 changes: 6 additions & 0 deletions XmlSchemaClassGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ public bool DisableComments
set { _configuration.DisableComments = value; }
}

public bool DoNotForceIsNullable
{
get { return _configuration.DoNotForceIsNullable; }
set { _configuration.DoNotForceIsNullable = value; }
}

public string PrivateMemberPrefix
{
get { return _configuration.PrivateMemberPrefix; }
Expand Down
6 changes: 6 additions & 0 deletions XmlSchemaClassGenerator/GeneratorConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ public void WriteLog(string message)

public bool DisableComments { get; set; }

/// <summary>
/// If True then do not force generator to emit IsNullable=true in XmlElement annotation
/// for nillable elements when element is nullable (minOccurs &lt; 1 or parent element is choice)
/// </summary>
public bool DoNotForceIsNullable { get; set; }

public string PrivateMemberPrefix { get; set; } = "_";

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion XmlSchemaClassGenerator/TypeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@ private IEnumerable<CodeAttributeDeclaration> GetAttributes(bool isArray)
}
}

if (IsNillable && !(IsCollection && Type is SimpleModel m && m.ValueType.IsValueType))
if (IsNillable && !(IsCollection && Type is SimpleModel m && m.ValueType.IsValueType) && !(IsNullable && Configuration.DoNotForceIsNullable))
{
attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(true)));
}
Expand Down

0 comments on commit 21bedfd

Please sign in to comment.