2009-08-07 24 views
20

Estoy usando xsd.exe para generar algunas clases C# de un archivo .xsd. Me encontré con el mismo problema que se trata aquí y en otros sitios donde xsd.exe genera matrices tipo [] en lugar de colecciones de listas genéricas para tipos en el archivo .xsd. Algunas personas han sugerido que svcutil.exe se puede usar como reemplazo de xsd.exe si pasa el parámetro/dataContractOnly a svcutil.exe. Sin embargo, parece que esas personas están equivocadas porque svcutil.exe realmente genera las propiedades de matriz System.Xml.XmlNode [] en lugar de crear tipos basados ​​en el esquema en el archivo .xsd.¿Es svcutil.exe un reemplazo para xsd.exe?

Por ejemplo, dado este esquema simple .xsd:

<?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/clases Example.xsd' genera:

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: Código/dataContractOnly/serializador: XmlSerializer/importXmlTypes /collectionType:System.Collections.Generic.List`1 Example.xsd' genera:

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. ¿Realmente se supone que svcutil.exe es un reemplazo para xsd.exe? La salida generada parece ser bastante diferente.

  2. En este punto, parece que tendré que usar xsd.exe para crear clases desde mi archivo .xsd y luego modificar manualmente el código para obtenerlo en la forma que quiero. Me doy cuenta de que usar código puramente generado sería ideal, pero me preguntaba si otras personas están usando xsd.exe como punto de partida y luego trabajando desde allí o si necesito considerar otro enfoque por completo.

  3. ¿Hay alguna actualización de xsd.exe en Visual Studio 2010?

+0

svcutil no fue pensado como un reemplazo para xsd.exe. Para acercarse lo más posible, intente utilizar los conmutadores '/ dataContractOnly' y '/ serializer: XmlSerializer'. –

+0

ServiceUtil se confunde con la opción 'xs: all'. Si su XSD fuera a usar 'xs: sequence', svcUtil generaría la salida adecuada. De los documentos del serializador de contrato de datos y svcUtil: xs: all - Forbidden. http://msdn.microsoft.com/en-us/library/ms733112(v=vs.110).aspx – jessehouwing

+0

Puede encontrar mi respuesta a la misma pregunta [aquí] [1] [1 ]: http://stackoverflow.com/a/24557248/1125467 – vivekp

Respuesta

6

Sí, svcutil.exe puede ser utilizado como un reemplazo para xsd.exe pero suena como usted está teniendo problemas para conseguir colecciones genéricas que se generen. svcutil.exe tiene un interruptor collectionType que le permite especificar el tipo que se utilizará para una colección:

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

Agregué un ejemplo anterior para mostrar el resultado que se genera. – jameswelle

1

He probado los mismos comandos en otro esquema, ang recibido resultados similares "chatarra" de svcutil. Entonces, podría ser una forma de hacer que funcione como xsd.exe, pero hasta ahora todo lo que he visto son mucho menos útiles.


respuesta Actualización: He encontrado que muchas de estas matrices genéricas de los nodos XML fueron reemplazados por tipos fuertes cuando de todos los XSD que se hace referencia se incluyen la fuerza. En mi caso, tengo muchos archivos xsd referenciados entre sí, pero svcutil parece no incluirlos. Tuve que decirle que use * .xsd para obtenerlos a todos.

+0

¿fue esta una respuesta a la pregunta? Parece una pregunta en sí misma. Si es así, debe hacer una pregunta por separado. –

+0

Lo actualicé, pero después de revisar la pregunta más, creo que mi respuesta aún no es aplicable ya que su esquema parece ser todo incluido, a diferencia de los que estoy trabajando. –

+1

ni svcutil ni xsd.exe harán referencia automáticamente a los archivos incluidos. En ambos casos, debes decirles qué archivos mirar. –

2

Simplemente crearía su propio xsd.exe.En este momento tiene problemas para pegar, pero si copia el código en tu principal:

 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; 
        } 
       } 
      } 
     } 
    } 

} 

}

+0

-1: ¿soluciona esto su problema? –

4

Aclaración

respuesta de Andrew Hare anterior se trabajo, pero el comando de ejemplo que jameswelle pegar apenas sobre su última sección del código:

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

hace no trabajo porque, as stated on MSDN, '. . .el /r y /ct conmutadores para tipos de referencia son para generar contratos de datos. Estos interruptores no funcionan cuando se usa XmlSerializer. '

HTH.