diff --git a/README.md b/README.md
index c1d01b65..0351c34d 100644
--- a/README.md
+++ b/README.md
@@ -146,6 +146,16 @@ Using the optional `|` syntax of the `-n` command line option you can map indivi
dotnet-xscgen.exe -n "|a.xsd=Example.NamespaceA" -n "|b.xsd=Example.NamespaceB" a.xsd b.xsd
```
+#### Mapping empty XML namespaces
+
+In order to provide a C# namespace name for an empty XML namespace you can specify it on the command line like this:
+
+```
+XmlSchemaClassGenerator.Console.exe -n =Example example.xsd
+```
+
+Note the space between `-n` and `=Example`.
+
Nullables
---------------------------------
diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs
index 7296b2c7..fd12c561 100644
--- a/XmlSchemaClassGenerator.Console/Program.cs
+++ b/XmlSchemaClassGenerator.Console/Program.cs
@@ -30,6 +30,7 @@ static void Main(string[] args)
var entityFramework = false;
var interfaces = true;
var pascal = true;
+ var assembly = false;
var collectionType = typeof(Collection<>);
Type collectionImplementationType = null;
var codeTypeReferenceOptions = default(CodeTypeReferenceOptions);
@@ -75,6 +76,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l
{ "f|ef", "generate Entity Framework Code First compatible classes", v => entityFramework = v != null },
{ "t|interface", "generate interfaces for groups and attribute groups (default is enabled)", v => interfaces = v != null },
{ "a|pascal", "use Pascal case for class and property names (default is enabled)", v => pascal = v != null },
+ { "av|assemblyVisible", "use the internal visibility modifier (default is false)", v => assembly = v != null },
{ "u|enableUpaCheck", "should XmlSchemaSet check for Unique Particle Attribution (UPA) (default is enabled)", v => enableUpaCheck = v != null },
{ "ct|collectionType=", "collection type to use (default is " + typeof(Collection<>).FullName + ")", v => collectionType = v == null ? typeof(Collection<>) : Type.GetType(v, true) },
{ "cit|collectionImplementationType=", "the default collection type implementation to use (default is null)", v => collectionImplementationType = v == null ? null : Type.GetType(v, true) },
@@ -121,6 +123,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l
EntityFramework = entityFramework,
GenerateInterfaces = interfaces,
NamingScheme = pascal ? NamingScheme.PascalCase : NamingScheme.Direct,
+ AssemblyVisible=assembly,
CollectionType = collectionType,
CollectionImplementationType = collectionImplementationType,
CodeTypeReferenceOptions = codeTypeReferenceOptions,
diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs
index bf6bac67..b830e08d 100644
--- a/XmlSchemaClassGenerator.Tests/XmlTests.cs
+++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs
@@ -41,9 +41,10 @@ private IEnumerable ConvertXml(string name, string xsd, Generator genera
DataAnnotationMode = generatorPrototype.DataAnnotationMode,
GenerateDesignerCategoryAttribute = generatorPrototype.GenerateDesignerCategoryAttribute,
EntityFramework = generatorPrototype.EntityFramework,
+ AssemblyVisible = generatorPrototype.AssemblyVisible,
GenerateInterfaces = generatorPrototype.GenerateInterfaces,
MemberVisitor = generatorPrototype.MemberVisitor,
- CodeTypeReferenceOptions = generatorPrototype.CodeTypeReferenceOptions
+ CodeTypeReferenceOptions = generatorPrototype.CodeTypeReferenceOptions
};
var set = new XmlSchemaSet();
@@ -389,12 +390,12 @@ public void DontGenerateElementForEmptyCollectionInChoice()
}
- [Theory]
- [InlineData(CodeTypeReferenceOptions.GlobalReference, "[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]")]
- [InlineData((CodeTypeReferenceOptions)0, "[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]")]
- public void EditorBrowsableAttributeRespectsCodeTypeReferenceOptions(CodeTypeReferenceOptions codeTypeReferenceOptions, string expectedLine)
- {
- const string xsd = @"
+ [Theory]
+ [InlineData(CodeTypeReferenceOptions.GlobalReference, "[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]")]
+ [InlineData((CodeTypeReferenceOptions)0, "[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]")]
+ public void EditorBrowsableAttributeRespectsCodeTypeReferenceOptions(CodeTypeReferenceOptions codeTypeReferenceOptions, string expectedLine)
+ {
+ const string xsd = @"
@@ -409,26 +410,26 @@ public void EditorBrowsableAttributeRespectsCodeTypeReferenceOptions(CodeTypeRef
";
- var generatedType = ConvertXml(nameof(EditorBrowsableAttributeRespectsCodeTypeReferenceOptions), xsd, new Generator
- {
- CodeTypeReferenceOptions = codeTypeReferenceOptions,
- GenerateNullables = true,
- GenerateInterfaces = false,
- NamespaceProvider = new NamespaceProvider
- {
- GenerateNamespace = key => "Test"
- }
- });
-
- Assert.Contains(
- expectedLine,
- generatedType.First());
- }
-
- [Fact]
- public void MixedTypeMustNotCollideWithExistingMembers()
- {
- const string xsd = @"
+ var generatedType = ConvertXml(nameof(EditorBrowsableAttributeRespectsCodeTypeReferenceOptions), xsd, new Generator
+ {
+ CodeTypeReferenceOptions = codeTypeReferenceOptions,
+ GenerateNullables = true,
+ GenerateInterfaces = false,
+ NamespaceProvider = new NamespaceProvider
+ {
+ GenerateNamespace = key => "Test"
+ }
+ });
+
+ Assert.Contains(
+ expectedLine,
+ generatedType.First());
+ }
+
+ [Fact]
+ public void MixedTypeMustNotCollideWithExistingMembers()
+ {
+ const string xsd = @"
@@ -437,23 +438,23 @@ public void MixedTypeMustNotCollideWithExistingMembers()
";
- var generatedType = ConvertXml(nameof(MixedTypeMustNotCollideWithExistingMembers), xsd, new Generator
- {
- NamespaceProvider = new NamespaceProvider
- {
- GenerateNamespace = key => "Test"
- }
- });
-
- Assert.Contains(
- @"public string[] Text_1 { get; set; }",
- generatedType.First());
- }
-
- [Fact]
- public void MixedTypeMustNotCollideWithContainingTypeName()
- {
- const string xsd = @"
+ var generatedType = ConvertXml(nameof(MixedTypeMustNotCollideWithExistingMembers), xsd, new Generator
+ {
+ NamespaceProvider = new NamespaceProvider
+ {
+ GenerateNamespace = key => "Test"
+ }
+ });
+
+ Assert.Contains(
+ @"public string[] Text_1 { get; set; }",
+ generatedType.First());
+ }
+
+ [Fact]
+ public void MixedTypeMustNotCollideWithContainingTypeName()
+ {
+ const string xsd = @"
@@ -461,30 +462,30 @@ public void MixedTypeMustNotCollideWithContainingTypeName()
";
- var generatedType = ConvertXml(nameof(MixedTypeMustNotCollideWithExistingMembers), xsd, new Generator
- {
- NamespaceProvider = new NamespaceProvider
- {
- GenerateNamespace = key => "Test"
- }
- });
-
- Assert.Contains(
- @"public string[] Text_1 { get; set; }",
- generatedType.First());
- }
-
- [Theory]
- [InlineData(@"xml/sameattributenames.xsd", @"xml/sameattributenames_import.xsd")]
- public void CollidingAttributeAndPropertyNamesCanBeResolved(params string[] files)
- {
- // Compilation would previously throw due to duplicate type name within type
- var assembly = Compiler.GenerateFiles("AttributesWithSameName", files);
-
- Assert.NotNull(assembly);
- }
-
- [Fact]
+ var generatedType = ConvertXml(nameof(MixedTypeMustNotCollideWithExistingMembers), xsd, new Generator
+ {
+ NamespaceProvider = new NamespaceProvider
+ {
+ GenerateNamespace = key => "Test"
+ }
+ });
+
+ Assert.Contains(
+ @"public string[] Text_1 { get; set; }",
+ generatedType.First());
+ }
+
+ [Theory]
+ [InlineData(@"xml/sameattributenames.xsd", @"xml/sameattributenames_import.xsd")]
+ public void CollidingAttributeAndPropertyNamesCanBeResolved(params string[] files)
+ {
+ // Compilation would previously throw due to duplicate type name within type
+ var assembly = Compiler.GenerateFiles("AttributesWithSameName", files);
+
+ Assert.NotNull(assembly);
+ }
+
+ [Fact]
public void ComplexTypeWithAttributeGroupExtension()
{
const string xsd = @"
@@ -630,6 +631,50 @@ public void ChoiceMembersAreNullable()
Assert.Contains("Opt4Specified", content);
}
+ [Fact]
+ public void AssemblyVisibleIsInternal()
+ {
+ // We test to see whether choices which are part of a larger ComplexType are marked as nullable.
+ // Because nullability isn't directly exposed in the generated C#, we use "XXXSpecified" on a value type
+ // as a proxy.
+
+ const string xsd = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+ var generator = new Generator
+ {
+ NamespaceProvider = new NamespaceProvider
+ {
+ GenerateNamespace = key => "Test"
+ },
+ AssemblyVisible = true
+ };
+ var contents = ConvertXml(nameof(ComplexTypeWithAttributeGroupExtension), xsd, generator);
+ var content = Assert.Single(contents);
+
+ Assert.Contains("internal partial class RootSub", content);
+ Assert.Contains("internal partial class Root", content);
+ }
+
private static void CompareOutput(string expected, string actual)
{
string Normalize(string input) => Regex.Replace(input, @"[ \t]*\r\n", "\n");
diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs
index b96a8884..cb9fce25 100644
--- a/XmlSchemaClassGenerator/Generator.cs
+++ b/XmlSchemaClassGenerator/Generator.cs
@@ -75,6 +75,12 @@ public NamingScheme NamingScheme
set { _configuration.NamingScheme = value; }
}
+ public bool AssemblyVisible
+ {
+ get { return _configuration.AssemblyVisible; }
+ set { _configuration.AssemblyVisible = value; }
+ }
+
///
/// Emit the "Order" attribute value for XmlElementAttribute to ensure the correct order
/// of the serialized XML elements.
diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs
index 343f7db4..497fd4f4 100644
--- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs
+++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs
@@ -129,7 +129,10 @@ public GeneratorConfiguration()
/// Generate from XML comments.
///
public bool GenerateDescriptionAttribute { get; set; }
-
+ ///
+ /// Generate types as internal if true. public otherwise.
+ ///
+ public bool AssemblyVisible { get; set; }
///
/// Generator Code reference options
///
@@ -172,7 +175,7 @@ public void WriteLog(string message)
public bool DisableComments { get; set; }
public bool DoNotUseUnderscoreInPrivateMemberNames { get; set; }
-
+
///
/// Check for Unique Particle Attribution (UPA) violations
///
diff --git a/XmlSchemaClassGenerator/ModelBuilder.cs b/XmlSchemaClassGenerator/ModelBuilder.cs
index e8c69ba2..81347c5e 100644
--- a/XmlSchemaClassGenerator/ModelBuilder.cs
+++ b/XmlSchemaClassGenerator/ModelBuilder.cs
@@ -448,6 +448,7 @@ private IEnumerable CreatePropertiesForAttributes(Uri source, Typ
IsAttribute = true,
IsNullable = attribute.Use != XmlSchemaUse.Required,
DefaultValue = attribute.DefaultValue ?? (attribute.Use != XmlSchemaUse.Optional ? attribute.FixedValue : null),
+ FixedValue = attribute.FixedValue,
Form = attribute.Form == XmlSchemaForm.None ? attribute.GetSchema().AttributeFormDefault : attribute.Form,
XmlNamespace = attribute.QualifiedName.Namespace != "" && attribute.QualifiedName.Namespace != typeModel.XmlSchemaName.Namespace ? attribute.QualifiedName.Namespace : null,
};
@@ -522,6 +523,7 @@ private IEnumerable CreatePropertiesForElements(Uri source, TypeM
IsNullable = item.MinOccurs < 1.0m || (item.XmlParent is XmlSchemaChoice),
IsCollection = item.MaxOccurs > 1.0m || particle.MaxOccurs > 1.0m, // http://msdn.microsoft.com/en-us/library/vstudio/d3hx2s7e(v=vs.100).aspx
DefaultValue = element.DefaultValue ?? ((item.MinOccurs >= 1.0m && !(item.XmlParent is XmlSchemaChoice)) ? element.FixedValue : null),
+ FixedValue = element.FixedValue,
Form = element.Form == XmlSchemaForm.None ? element.GetSchema().ElementFormDefault : element.Form,
XmlNamespace = element.QualifiedName.Namespace != "" && element.QualifiedName.Namespace != typeModel.XmlSchemaName.Namespace ? element.QualifiedName.Namespace : null,
XmlParticle = item.XmlParticle,
diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs
index 225e4501..76eba060 100644
--- a/XmlSchemaClassGenerator/TypeModel.cs
+++ b/XmlSchemaClassGenerator/TypeModel.cs
@@ -272,6 +272,11 @@ public override CodeTypeDeclaration Generate()
classDeclaration.IsClass = true;
classDeclaration.IsPartial = true;
+ if (Configuration.AssemblyVisible)
+ {
+ classDeclaration.TypeAttributes = (classDeclaration.TypeAttributes & ~System.Reflection.TypeAttributes.VisibilityMask) | System.Reflection.TypeAttributes.NestedAssembly;
+ }
+
if (Configuration.EnableDataBinding)
{
@@ -382,29 +387,29 @@ public override CodeTypeDeclaration Generate()
keyProperty.IsKey = true;
}
- foreach (var property in Properties.GroupBy(x => x.Name))
- {
- var propertyIndex = 0;
- foreach (var p in property)
- {
- if (propertyIndex > 0)
- {
- p.Name += $"_{propertyIndex}";
- }
- p.AddMembersTo(classDeclaration, Configuration.EnableDataBinding);
- propertyIndex++;
- }
- }
-
- if (IsMixed && (BaseClass == null || (BaseClass is ClassModel && !AllBaseClasses.Any(b => b.IsMixed))))
- {
- var propName = "Text";
-
- // To not collide with any existing members
- for (var propertyIndex = 1; Properties.Any(x => x.Name.Equals(propName, StringComparison.Ordinal)) || propName.Equals(classDeclaration.Name, StringComparison.Ordinal); propertyIndex++)
- {
- propName = $"Text_{propertyIndex}";
- }
+ foreach (var property in Properties.GroupBy(x => x.Name))
+ {
+ var propertyIndex = 0;
+ foreach (var p in property)
+ {
+ if (propertyIndex > 0)
+ {
+ p.Name += $"_{propertyIndex}";
+ }
+ p.AddMembersTo(classDeclaration, Configuration.EnableDataBinding);
+ propertyIndex++;
+ }
+ }
+
+ if (IsMixed && (BaseClass == null || (BaseClass is ClassModel && !AllBaseClasses.Any(b => b.IsMixed))))
+ {
+ var propName = "Text";
+
+ // To not collide with any existing members
+ for (var propertyIndex = 1; Properties.Any(x => x.Name.Equals(propName, StringComparison.Ordinal)) || propName.Equals(classDeclaration.Name, StringComparison.Ordinal); propertyIndex++)
+ {
+ propName = $"Text_{propertyIndex}";
+ }
var text = new CodeMemberField(typeof(string[]), propName);
// hack to generate automatic property
text.Name += " { get; set; }";
@@ -494,6 +499,7 @@ public class PropertyModel
public bool IsNillable { get; set; }
public bool IsCollection { get; set; }
public string DefaultValue { get; set; }
+ public string FixedValue { get; set; }
public XmlSchemaForm Form { get; set; }
public string XmlNamespace { get; set; }
public List Documentation { get; private set; }
@@ -893,7 +899,7 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
var editorBrowsableAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(EditorBrowsableAttribute), Configuration.CodeTypeReferenceOptions));
editorBrowsableAttribute.Arguments.Add(new CodeAttributeArgument(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(new CodeTypeReference(typeof(EditorBrowsableState), Configuration.CodeTypeReferenceOptions)), "Never")));
- specifiedMember.CustomAttributes.Add(editorBrowsableAttribute);
+ specifiedMember.CustomAttributes.Add(editorBrowsableAttribute);
member.CustomAttributes.Add(editorBrowsableAttribute);
if (Configuration.EntityFramework) { member.CustomAttributes.Add(notMappedAttribute); }
}