Skip to content

Commit

Permalink
Merge pull request #143 from ivanpovazan/custom_ns_fix
Browse files Browse the repository at this point in the history
Improving namespace provider to correctly generate custom csharp namespaces
  • Loading branch information
mganss authored Oct 2, 2019
2 parents 5074d7a + 4d4deaa commit 7dd924b
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 20 deletions.
17 changes: 1 addition & 16 deletions XmlSchemaClassGenerator.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l
uris.AddRange(expandedGlob);
}

var namespaceMap = namespaces.Select(n => ParseNamespace(n, namespacePrefix)).ToNamespaceProvider(key =>
var namespaceMap = namespaces.Select(n => CodeUtilities.ParseNamespace(n, namespacePrefix)).ToNamespaceProvider(key =>
{
var xn = key.XmlSchemaNamespace;
var name = string.Join(".", xn.Split('/').Where(p => p != "schema" && GeneratorConfiguration.IdentifierRegex.IsMatch(p))
Expand Down Expand Up @@ -170,21 +170,6 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l
generator.Generate(uris);
}

static KeyValuePair<NamespaceKey, string> ParseNamespace(string nsArg, string namespacePrefix)
{
var parts = nsArg.Split(new[] { '=' }, 2);
var xmlNs = parts[0];
var netNs = parts[1];
var parts2 = xmlNs.Split(new[] { '|' }, 2);
var source = parts2.Length == 2 ? new Uri(parts2[1], UriKind.RelativeOrAbsolute) : null;
xmlNs = parts2[0];
if (!string.IsNullOrEmpty(namespacePrefix))
{
netNs = namespacePrefix + "." + netNs;
}
return new KeyValuePair<NamespaceKey, string>(new NamespaceKey(source, xmlNs), netNs);
}

static void ShowHelp(OptionSet p)
{
System.Console.WriteLine("Usage: dotnet xscgen [OPTIONS]+ xsdFile...");
Expand Down
38 changes: 38 additions & 0 deletions XmlSchemaClassGenerator.Tests/NamespaceProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,43 @@ public void NamespaceKeyComparableTest()
Assert.False(new NamespaceKey("http://test") <= null);
Assert.True(new NamespaceKey("http://test") != null);
}

[Theory]
[InlineData("http://www.w3.org/2001/XMLSchema", "test.xsd", "MyNamespace", "Test")]
[InlineData("http://www.w3.org/2001/XMLSchema", "test.xsd", "MyNamespace", null)]
[InlineData("http://www.w3.org/2001/XMLSchema", "test.xsd", "MyNamespace", "")]
[InlineData("", "test.xsd", "MyNamespace", "Test")]
[InlineData("", "test.xsd", "MyNamespace", null)]
[InlineData("", "test.xsd", "MyNamespace", "")]
[InlineData(null, "test.xsd", "MyNamespace", "Test")]
[InlineData(null, "test.xsd", "MyNamespace", null)]
[InlineData(null, "test.xsd", "MyNamespace", "")]
public void TestParseNamespaceUtilityMethod1(string xmlNs, string xmlSchema, string netNs, string netPrefix)
{
string customNsPattern = "{0}|{1}={2}";

var uri = new Uri(xmlSchema, UriKind.RelativeOrAbsolute);
var fullNetNs = (string.IsNullOrEmpty(netPrefix)) ? netNs : string.Join('.', netPrefix, netNs);

var expected = new KeyValuePair<NamespaceKey, string>(new NamespaceKey(uri, xmlNs), fullNetNs);
var actual = CodeUtilities.ParseNamespace(string.Format(customNsPattern, xmlNs, xmlSchema, netNs), netPrefix);

Assert.Equal(expected, actual);
}

[Theory]
[InlineData("test.xsd", "MyNamespace", "Test")]
[InlineData("test.xsd", "MyNamespace", null)]
[InlineData("test.xsd", "MyNamespace", "")]
public void TestParseNamespaceUtilityMethod2(string xmlSchema, string netNs, string netPrefix)
{
string customNsPattern = "{0}={1}";

var fullNetNs = (string.IsNullOrEmpty(netPrefix)) ? netNs : string.Join('.', netPrefix, netNs);
var expected = new KeyValuePair<NamespaceKey, string>(new NamespaceKey(null, xmlSchema), fullNetNs);
var actual = CodeUtilities.ParseNamespace(string.Format(customNsPattern, xmlSchema, netNs), netPrefix);

Assert.Equal(expected, actual);
}
}
}
65 changes: 63 additions & 2 deletions XmlSchemaClassGenerator.Tests/XmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,16 +370,77 @@ void TestCompareToXsd(Type t1, Type t2, string file)

[Fact, TestPriority(1)]
[UseCulture("en-US")]
public void TestBpmn()
public void TestCustomNamespaces()
{
string customNsPattern = "|{0}={1}";
string bpmnXsd = "BPMN20.xsd";
string semantXsd = "Semantic.xsd";
string bpmndiXsd = "BPMNDI.xsd";
string dcXsd = "DC.xsd";
string diXsd = "DI.xsd";

Dictionary<string, string> xsdToCsharpNsMap = new Dictionary<string, string>
{
{ bpmnXsd, "Namespace1" },
{ semantXsd, "Namespace1" },
{ bpmndiXsd, "Namespace2" },
{ dcXsd, "Namespace3" },
{ diXsd, "Namespace4" }
};

Dictionary<string, string> xsdToCsharpTypeMap = new Dictionary<string, string>
{
{ bpmnXsd, "TDefinitions" },
{ semantXsd, "TActivity" },
{ bpmndiXsd, "BPMNDiagram" },
{ dcXsd, "Font" },
{ diXsd, "DiagramElement" }
};

List<string> customNamespaceConfig = new List<string>();

foreach (var ns in xsdToCsharpNsMap)
customNamespaceConfig.Add(string.Format(customNsPattern, ns.Key, ns.Value));

var assembly = Compiler.Generate("Bpmn", BpmnPattern, new Generator
{
DataAnnotationMode = DataAnnotationMode.All,
GenerateNullables = true,
MemberVisitor = (member, model) => { }
MemberVisitor = (member, model) => { },
NamespaceProvider = customNamespaceConfig.Select(n => CodeUtilities.ParseNamespace(n, null)).ToNamespaceProvider()
});
Assert.NotNull(assembly);

Type type = null;

type = assembly.GetTypes().SingleOrDefault(t => t.Name == xsdToCsharpTypeMap[bpmnXsd]);
Assert.NotNull(type);
Assert.Equal(xsdToCsharpNsMap[bpmnXsd], type.Namespace);

type = assembly.GetTypes().SingleOrDefault(t => t.Name == xsdToCsharpTypeMap[semantXsd]);
Assert.NotNull(type);
Assert.Equal(xsdToCsharpNsMap[semantXsd], type.Namespace);

type = assembly.GetTypes().SingleOrDefault(t => t.Name == xsdToCsharpTypeMap[bpmndiXsd]);
Assert.NotNull(type);
Assert.Equal(xsdToCsharpNsMap[bpmndiXsd], type.Namespace);

type = assembly.GetTypes().SingleOrDefault(t => t.Name == xsdToCsharpTypeMap[dcXsd]);
Assert.NotNull(type);
Assert.Equal(xsdToCsharpNsMap[dcXsd], type.Namespace);

type = assembly.GetTypes().SingleOrDefault(t => t.Name == xsdToCsharpTypeMap[diXsd]);
Assert.NotNull(type);
Assert.Equal(xsdToCsharpNsMap[diXsd], type.Namespace);
}

[Fact, TestPriority(2)]
[UseCulture("en-US")]
public void TestBpmn()
{
var assembly = Compiler.Generate("Bpmn", BpmnPattern);
Assert.NotNull(assembly);

var type = assembly.GetTypes().SingleOrDefault(t => t.Name == "TDefinitions");
Assert.NotNull(type);

Expand Down
15 changes: 15 additions & 0 deletions XmlSchemaClassGenerator/CodeUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,20 @@ internal static string NormalizeNewlines(string text)
};

internal static Uri CreateUri(string uri) => string.IsNullOrEmpty(uri) ? null : new Uri(uri);

public static KeyValuePair<NamespaceKey, string> ParseNamespace(string nsArg, string namespacePrefix)
{
var parts = nsArg.Split(new[] { '=' }, 2);
var xmlNs = parts[0];
var netNs = parts[1];
var parts2 = xmlNs.Split(new[] { '|' }, 2);
var source = parts2.Length == 2 ? new Uri(parts2[1], UriKind.RelativeOrAbsolute) : null;
xmlNs = parts2[0];
if (!string.IsNullOrEmpty(namespacePrefix))
{
netNs = namespacePrefix + "." + netNs;
}
return new KeyValuePair<NamespaceKey, string>(new NamespaceKey(source, xmlNs), netNs);
}
}
}
42 changes: 40 additions & 2 deletions XmlSchemaClassGenerator/ModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,52 @@ public ModelBuilder(GeneratorConfiguration configuration, XmlSchemaSet set)
.DistinctBy(g => g.QualifiedName.ToString())
.ToDictionary(g => g.QualifiedName);

foreach (var globalType in set.GlobalTypes.Values.Cast<XmlSchemaType>())
List<XmlSchema> dependencyOrder = new List<XmlSchema>();
foreach (var schema in set.Schemas().Cast<XmlSchema>())
{
ResolveDependencies(schema, dependencyOrder);
}

foreach (var schema in dependencyOrder)
{
var types = set.GlobalTypes.Values.Cast<XmlSchemaType>().Where(s => s.GetSchema() == schema);
CreateTypes(types);
var elements = set.GlobalElements.Values.Cast<XmlSchemaElement>().Where(s => s.GetSchema() == schema);
CreateElements(elements);
}
}

private void ResolveDependencies(XmlSchema schema, List<XmlSchema> dependencyOrder)
{
if (dependencyOrder.Contains(schema))
return;

var imports = schema.Includes.OfType<XmlSchemaImport>();
if (imports.Any())
{
foreach (var import in imports)
{
if (import.Schema != null)
ResolveDependencies(import.Schema, dependencyOrder);
}
}
dependencyOrder.Add(schema);
}


private void CreateTypes(IEnumerable<XmlSchemaType> types)
{
foreach (var globalType in types)
{
var schema = globalType.GetSchema();
var source = CodeUtilities.CreateUri(schema?.SourceUri);
CreateTypeModel(source, globalType, globalType.QualifiedName);
}
}

foreach (var rootElement in set.GlobalElements.Values.Cast<XmlSchemaElement>())
private void CreateElements(IEnumerable<XmlSchemaElement> elements)
{
foreach (var rootElement in elements)
{
var rootSchema = rootElement.GetSchema();
var source = CodeUtilities.CreateUri(rootSchema.SourceUri);
Expand Down
3 changes: 3 additions & 0 deletions XmlSchemaClassGenerator/NamespaceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ public string FindNamespace(NamespaceKey key, string defaultNamespace = null)
var path = key.Source.IsAbsoluteUri ? key.Source.LocalPath : key.Source.OriginalString;
keyValues.Add(new NamespaceKey(new Uri(Path.GetFileName(path), UriKind.Relative)));

// Search for both file name and XmlSchemaNamespace pair
keyValues.Add(new NamespaceKey(new Uri(Path.GetFileName(path), UriKind.Relative), key.XmlSchemaNamespace));

// Search for XmlSchemaNamespace only
keyValues.Add(new NamespaceKey(key.XmlSchemaNamespace));

Expand Down

0 comments on commit 7dd924b

Please sign in to comment.