Tutorial :Is svcutil.exe a replacement for xsd.exe?


I am using xsd.exe to generate some c# classes from a .xsd file. I ran into the same issue that is covered here and on other sites where xsd.exe generates Type[] arrays instead of generic List collections for types in the .xsd file. Some people have suggested that svcutil.exe can be used as a replacement for xsd.exe if you pass the /dataContractOnly parameter to svcutil.exe. However, it seems like those people are mistaken because svcutil.exe actually generates System.Xml.XmlNode[] array properties instead of creating types based on the schema in the .xsd file.

For example, given this simple .xsd schema:

<?xml version="1.0" encoding="utf-8"?>  <xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"  elementFormDefault="qualified"  xmlns="http://tempuri.org/XMLSchema.xsd"  xmlns:mstns="http://tempuri.org/XMLSchema.xsd"  xmlns:xs="http://www.w3.org/2001/XMLSchema"  >      <xs:complexType name="Employee">          <xs:all>              <xs:element name="FirstName" type="xs:string"></xs:element>              <xs:element name="LastName" type="xs:string"></xs:element>          </xs:all>      </xs:complexType>        <xs:element name="Employees">          <xs:complexType>              <xs:sequence maxOccurs="unbounded">                  <xs:element name="Employee" type="Employee"></xs:element>              </xs:sequence>          </xs:complexType>      </xs:element>  </xs:schema>  

'xsd.exe /classes Example.xsd' generates:

public partial class Employees {        private Employee[] employeeField;        public Employee[] Employee {          get { return this.employeeField; }          set { this.employeeField = value; }      }  }    public partial class Employee {        private string firstNameField;        private string lastNameField;        public string FirstName {          get { return this.firstNameField; }          set { this.firstNameField = value; }      }        public string LastName {          get { return this.lastNameField; }          set { this.lastNameField = value; }      }  }  

'svcutil.exe /target:code /dataContractOnly /serializer:XmlSerializer /importXmlTypes /collectionType:System.Collections.Generic.List`1 Example.xsd' generates:

public partial class Employee : object, System.Runtime.Serialization.IExtensibleDataObject{        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;        private string FirstNameField;        private string LastNameField;        public System.Runtime.Serialization.ExtensionDataObject ExtensionData{          get{ return this.extensionDataField; }          set{ this.extensionDataField = value; }      }        public string FirstName{          get{ return this.FirstNameField; }          set{ this.FirstNameField = value; }      }        public string LastName{          get{ return this.LastNameField; }          set{ this.LastNameField = value; }      }  }    public partial class Employees : object, System.Xml.Serialization.IXmlSerializable{        private System.Xml.XmlNode[] nodesField;        private static System.Xml.XmlQualifiedName typeName = new System.Xml.XmlQualifiedName("Employees", "http://tempuri.org/XMLSchema.xsd");        public System.Xml.XmlNode[] Nodes{          get{ return this.nodesField; }          set{ this.nodesField = value; }      }        public void ReadXml(System.Xml.XmlReader reader){          this.nodesField = System.Runtime.Serialization.XmlSerializableServices.ReadNodes(reader);      }        public void WriteXml(System.Xml.XmlWriter writer){          System.Runtime.Serialization.XmlSerializableServices.WriteNodes(writer, this.Nodes);      }        public System.Xml.Schema.XmlSchema GetSchema(){          return null;      }        public static System.Xml.XmlQualifiedName ExportSchema(System.Xml.Schema.XmlSchemaSet schemas){          System.Runtime.Serialization.XmlSerializableServices.AddDefaultSchema(schemas, typeName);          return typeName;      }  }  
  1. Is svcutil.exe really supposed to be a replacement for xsd.exe? The output generated seems to be quite different.

  2. At this point, it looks like I will have to use xsd.exe to create classes from my .xsd file and then manually tweak the the code to get it in the form I want. I realize that using purely generated code would be ideal, but I was wondering if other people are using xsd.exe as a starting point and then working from there or if I need to consider another approach altogether?

  3. Are there any updates to xsd.exe in Visual Studio 2010?


Yes, svcutil.exe can be used as a replacement for xsd.exe but it sounds like you are having trouble getting generic collections to be generated. svcutil.exe has a collectionType switch that allows you to specify the type to be used for a collection:

svcutil /o:Svc.cs /ct:System.Collections.Generic.List`1 http://example.com  



Andrew Hare's answer above will work, but the example command that jameswelle pasted just above his last section of code:

svcutil.exe /target:code /dataContractOnly /serializer:XmlSerializer /importXmlTypes /collectionType:System.Collections.Generic.List`1 Example.xsd

does not work because, as stated on MSDN, '. . .the /r and /ct switches for referencing types are for generating data contracts. These switches do not work when using XmlSerializer.'



I would just create your own xsd.exe. Sorry having trouble pasting but if you copy this code into your main:

        XmlSchemas xsds = new XmlSchemas();          xsds.Add(xsd);          xsds.Compile(null, true);          XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds);            // create the codedom          CodeNamespace codeNamespace = new CodeNamespace(strNamespace);          XmlCodeExporter codeExporter = new XmlCodeExporter(codeNamespace);            List<XmlTypeMapping> maps = new List<XmlTypeMapping>();          foreach (XmlSchemaType schemaType in xsd.SchemaTypes.Values)          {              maps.Add(schemaImporter.ImportSchemaType(schemaType.QualifiedName));          }          foreach (XmlSchemaElement schemaElement in xsd.Elements.Values)          {              maps.Add(schemaImporter.ImportTypeMapping(schemaElement.QualifiedName));          }          foreach (XmlTypeMapping map in maps)          {              codeExporter.ExportTypeMapping(map);          }            ReplaceArrayWithList(codeNamespace);            // Check for invalid characters in identifiers          CodeGenerator.ValidateIdentifiers(codeNamespace);            // output the C# code          CSharpCodeProvider codeProvider = new CSharpCodeProvider();            using (StreamWriter writer = new StreamWriter(strCsPath, false))          {              codeProvider.GenerateCodeFromNamespace(codeNamespace, writer, new CodeGeneratorOptions());          }      }      private static void ReplaceArrayWithList(CodeNamespace codeNamespace)      {          codeNamespace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));          foreach (CodeTypeDeclaration codeType in codeNamespace.Types)          {              foreach (CodeTypeMember member in codeType.Members)              {                  if (member is CodeMemberField)                  {                      CodeMemberField field = (CodeMemberField)member;                      if (field.Type.ArrayRank > 0)                      {                          CodeTypeReference type = new CodeTypeReference();                          type.BaseType = "List<" + field.Type.BaseType + ">";                          field.Type = type;                      }                  }                  if (member is CodeMemberProperty)                  {                      CodeMemberProperty property = (CodeMemberProperty)member;                      if (property.Type.ArrayRank > 0)                      {                          CodeTypeReference type = new CodeTypeReference();                          type.BaseType = "List<" + property.Type.BaseType + ">";                          property.Type = type;                      }                  }              }          }      }    }  



I have tested the same commands on another schema, ang received similar "junk" results from svcutil. So, the might be a way to make it work like xsd.exe, but so far all Ive seen are far less useful ones.

Updated answer: I found that many of these generic arrays of xml nodes were replaced by strong types when all the referenced XSD's are forcibly included. In my case, i have many xsd files all referenced by each other, but svcutil doesnt seem to include them. i had to instead tell it to use *.xsd to get them all.


I have found Xsd2Code to be much better than xsd.exe does does exactly what you need. See here: http://xsd2code.codeplex.com/

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »