From 8431aacf5f943284175e580e73fe3dca2080ef16 Mon Sep 17 00:00:00 2001 From: Michael Ganss Date: Fri, 1 Jan 2016 11:32:34 +0100 Subject: [PATCH] Support substitution groups --- XmlSchemaClassGenerator.Tests/AssertEx.cs | 2 +- .../XmlSchemaClassGenerator.Tests.csproj | 4 + XmlSchemaClassGenerator.Tests/XmlTests.cs | 2 +- .../xsd/is24immotransfer/is24immotransfer.xsd | 315 +++--------------- XmlSchemaClassGenerator/Generator.cs | 1 + XmlSchemaClassGenerator/TypeModel.cs | 106 +++--- 6 files changed, 127 insertions(+), 303 deletions(-) diff --git a/XmlSchemaClassGenerator.Tests/AssertEx.cs b/XmlSchemaClassGenerator.Tests/AssertEx.cs index b1ba7b28..73d418ad 100644 --- a/XmlSchemaClassGenerator.Tests/AssertEx.cs +++ b/XmlSchemaClassGenerator.Tests/AssertEx.cs @@ -71,7 +71,7 @@ public static void Equal(object o1, object o2) } else { - foreach (var prop in type1.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead)) + foreach (var prop in type1.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && !p.GetIndexParameters().Any())) { var val1 = prop.GetValue(o1); var val2 = prop.GetValue(o2); diff --git a/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj b/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj index b3b74da9..8b6956fc 100644 --- a/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj +++ b/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj @@ -226,6 +226,10 @@ Designer PreserveNewest + + Designer + PreserveNewest + Designer PreserveNewest diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index c36c0c9e..0e412c09 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -136,7 +136,7 @@ private void DeserializeSampleXml(string pattern, Assembly assembly) set.Compile(); - foreach (var rootElement in set.GlobalElements.Values.Cast()) + foreach (var rootElement in set.GlobalElements.Values.Cast().Where(e => !e.IsAbstract)) { var type = FindType(assembly, rootElement.QualifiedName); var serializer = new XmlSerializer(type); diff --git a/XmlSchemaClassGenerator.Tests/xsd/is24immotransfer/is24immotransfer.xsd b/XmlSchemaClassGenerator.Tests/xsd/is24immotransfer/is24immotransfer.xsd index 31fa6380..03e29f98 100644 --- a/XmlSchemaClassGenerator.Tests/xsd/is24immotransfer/is24immotransfer.xsd +++ b/XmlSchemaClassGenerator.Tests/xsd/is24immotransfer/is24immotransfer.xsd @@ -134,8 +134,8 @@ - Freitext, maximal 2000 Zeichen. - Zur Formatierung wird als HTML-Tag nur 'BR' unterstuetzt. + Freitext, maximal 2000 Zeichen. + Zur Formatierung wird als HTML-Tag nur 'BR' unterstuetzt. CDATA-Abschnitte werden nicht unterstuetzt. @@ -195,7 +195,7 @@ - + positive natuerliche Zahl, zweistellig @@ -213,7 +213,7 @@ - + positive natuerliche Zahl, dreistellig @@ -1802,7 +1802,7 @@ - entspricht 'ja' + entspricht 'ja' (aus Kompatibilitaetsgruenden, wird in zukuenftigen Versionen nicht mehr unterstuetzt) @@ -1810,7 +1810,7 @@ - entspricht 'nein' + entspricht 'nein' (aus Kompatibilitaetsgruenden, wird in zukuenftigen Versionen nicht mehr unterstuetzt) @@ -1921,7 +1921,7 @@ - + @@ -2150,7 +2150,7 @@ - aus Kompatibilitaetsgruenden weiter vorhanden: Benutze stattdessen 'Reihenmittelhaus' oder 'Reiheneckhaus' + aus Kompatibilitaetsgruenden weiter vorhanden: Benutze stattdessen 'Reihenmittelhaus' oder 'Reiheneckhaus' (wird in zukuenftigen Versionen nicht mehr unterstuetzt) @@ -2158,7 +2158,7 @@ - aus Kompatibilitaetsgruenden weiter vorhanden: Benutze stattdessen 'Mehrfamilienhaus' + aus Kompatibilitaetsgruenden weiter vorhanden: Benutze stattdessen 'Mehrfamilienhaus' (wird in zukuenftigen Versionen nicht mehr unterstuetzt) @@ -2203,7 +2203,7 @@ - Alle Nutzungsarten (Objektkategorie 2) fuer Grundstuecke + Alle Nutzungsarten (Objektkategorie 2) fuer Grundstuecke des alten allgemeinen Grundstueckstyps @@ -2399,7 +2399,7 @@ - Garagen/Stellplatz-Kategorien fuer Garagen/Stellplaetze von Hauser-, Wohnungs- und + Garagen/Stellplatz-Kategorien fuer Garagen/Stellplaetze von Hauser-, Wohnungs- und WAZ-Typen @@ -2516,10 +2516,8 @@ - - - - + + @@ -2552,14 +2550,14 @@ Zusaetzliche Angabe der Heizkosten / Warmwasser, monatlich. - Wenn Sie die Heizkosten angeben, dann geben Sie bitte auch an, ob diese in den Nebenkosten enthalten sind. + Wenn Sie die Heizkosten angeben, dann geben Sie bitte auch an, ob diese in den Nebenkosten enthalten sind. - Das Attribut besagt, ob die Nebenkosten die Heizkosten enthalten. + Das Attribut besagt, ob die Nebenkosten die Heizkosten enthalten. Wenn Sie die Heizkosten angeben, dann geben Sie bitte auch an, ob diese in den Nebenkosten enthalten sind. @@ -2575,18 +2573,18 @@ - + - + - + - + @@ -2594,13 +2592,13 @@ - + - + - + @@ -2610,10 +2608,10 @@ - + - + @@ -2623,10 +2621,10 @@ - + - + @@ -2634,14 +2632,14 @@ - + - + @@ -2657,7 +2655,7 @@ - + @@ -2759,22 +2757,8 @@ Empfohlene Nutzungen fuer Grundstuecke/Wohnen - - - - - - - - - - - - - - - - + + @@ -2782,31 +2766,8 @@ Empfohlene Nutzungen fuer Grundstuecke/Gewerbe - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -2979,7 +2940,7 @@ - aus Kompatibilitaetsgruenden nur als 'optional' deklariert: + aus Kompatibilitaetsgruenden nur als 'optional' deklariert: Der Wert sollte aber angegeben werden. @@ -3280,42 +3241,14 @@ - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - + + @@ -3324,113 +3257,32 @@ - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - entspricht: Seniorengerechtes Wohnen - - - + + - - - - - - - - - - - - - - - - - - - - - - - + + @@ -3499,34 +3351,8 @@ - - - - - - - - - - - - - - - - - - - - Provisionstext, -hinweis und -pflichtig-Flag werden fuer Typenhaeuser nicht unterstuetzt - - - - - Provisionstext, -hinweis und -pflichtig-Flag werden fuer Typenhaeuser nicht unterstuetzt - - - + + @@ -3547,23 +3373,8 @@ - - - - - - - - - - - - - - - - - + + @@ -3584,24 +3395,8 @@ - - - - - - - - - - - - - - - - - - + + @@ -3673,7 +3468,7 @@ - + @@ -3692,11 +3487,11 @@ - + - + diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 0b2db114..6e5dcdb3 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -479,6 +479,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaAnnotated type, XmlQualif IsAbstract = complexType.IsAbstract, IsAnonymous = complexType.QualifiedName.Name == "", IsMixed = complexType.IsMixed, + IsSubstitution = complexType.Parent is XmlSchemaElement && !((XmlSchemaElement)complexType.Parent).SubstitutionGroup.IsEmpty, EnableDataBinding = EnableDataBinding, }; diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index 222cfa91..33b449d0 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -193,6 +193,7 @@ public class ClassModel : TypeModel { public bool IsAbstract { get; set; } public bool IsMixed { get; set; } + public bool IsSubstitution { get; set; } public TypeModel BaseClass { get; set; } public List Properties { get; set; } public List Interfaces { get; set; } @@ -781,8 +782,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi typeDeclaration.Members.Add(specifiedProperty); } - var attribute = GetAttribute(isArray); - member.CustomAttributes.Add(attribute); + var attributes = GetAttributes(isArray).ToArray(); + member.CustomAttributes.AddRange(attributes); // initialize List<> if (IsCollection || isArray) @@ -806,11 +807,14 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi if (isArray) { var arrayItemProperty = typeClassModel.Properties[0]; - var propertyAttribute = arrayItemProperty.GetAttribute(false); + var propertyAttributes = arrayItemProperty.GetAttributes(false).ToList(); // HACK: repackage as ArrayItemAttribute - var arrayItemAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlArrayItemAttribute)), - propertyAttribute.Arguments.Cast().Where(x => !string.Equals(x.Name, "Order", StringComparison.Ordinal)).ToArray()); - member.CustomAttributes.Add(arrayItemAttribute); + foreach (var propertyAttribute in propertyAttributes) + { + var arrayItemAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlArrayItemAttribute)), + propertyAttribute.Arguments.Cast().Where(x => !string.Equals(x.Name, "Order", StringComparison.Ordinal)).ToArray()); + member.CustomAttributes.Add(arrayItemAttribute); + } } if (IsKey) @@ -825,79 +829,99 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi } } - private CodeAttributeDeclaration GetAttribute(bool isArray) + private IEnumerable GetAttributes(bool isArray) { - CodeAttributeDeclaration attribute; + var attributes = new List(); if (IsKey && XmlSchemaName == null) { - attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlIgnoreAttribute))); - return attribute; + attributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlIgnoreAttribute)))); + return attributes; } if (IsAttribute) { if (IsAny) { - attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlAnyAttributeAttribute))); + attributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlAnyAttributeAttribute)))); } else { - attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlAttributeAttribute)), - new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name))); + attributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlAttributeAttribute)), + new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)))); } } else if (!isArray) { if (IsAny) { - attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlAnyElementAttribute))); + attributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlAnyElementAttribute)))); } else { - attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlElementAttribute)), - new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name))); + var classType = PropertyType as ClassModel; + if (classType != null && classType.IsAbstract && classType.DerivedTypes.Any()) + { + var derivedTypes = classType.GetAllDerivedTypes().Where(t => t.IsSubstitution); + foreach (var derivedType in derivedTypes) + { + var derivedAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlElementAttribute)), + new CodeAttributeArgument(new CodePrimitiveExpression(derivedType.XmlSchemaName.Name)), + new CodeAttributeArgument("Type", new CodeTypeOfExpression(derivedType.GetReferenceFor(OwningType.Namespace, false)))); + if (Order != null) + derivedAttribute.Arguments.Add(new CodeAttributeArgument("Order", + new CodePrimitiveExpression(Order.Value))); + attributes.Add(derivedAttribute); + } + } + + var attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlElementAttribute)), + new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name))); if (Order != null) attribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(Order.Value))); + attributes.Add(attribute); } } else { - attribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlArrayAttribute)), - new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name))); + attributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(XmlArrayAttribute)), + new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)))); } - if (Form == XmlSchemaForm.Qualified) - { - attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(OwningType.XmlSchemaName.Namespace))); - } - else if (XmlNamespace != null) - { - attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(XmlNamespace))); - } - else if (!IsAny) + foreach (var attribute in attributes) { - attribute.Arguments.Add(new CodeAttributeArgument("Form", - new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(new CodeTypeReference(typeof(XmlSchemaForm))), - "Unqualified"))); - } + if (Form == XmlSchemaForm.Qualified) + { + attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(OwningType.XmlSchemaName.Namespace))); + } + else if (XmlNamespace != null) + { + attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(XmlNamespace))); + } + else if (!IsAny) + { + attribute.Arguments.Add(new CodeAttributeArgument("Form", + new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(new CodeTypeReference(typeof(XmlSchemaForm))), + "Unqualified"))); + } - if (IsNillable) - attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(true))); + if (IsNillable) + attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(true))); - var simpleModel = Type as SimpleModel; - if (simpleModel != null && simpleModel.UseDataTypeAttribute) - { - var name = Type.XmlSchemaType.GetQualifiedName(); - if (name.Namespace == XmlSchema.Namespace) + var simpleModel = Type as SimpleModel; + if (simpleModel != null && simpleModel.UseDataTypeAttribute) { - var dataType = new CodeAttributeArgument("DataType", new CodePrimitiveExpression(name.Name)); - attribute.Arguments.Add(dataType); + var name = Type.XmlSchemaType.GetQualifiedName(); + if (name.Namespace == XmlSchema.Namespace) + { + var dataType = new CodeAttributeArgument("DataType", new CodePrimitiveExpression(name.Name)); + attribute.Arguments.Add(dataType); + } } } - return attribute; + return attributes; } }