c# xml xsd xsd.exe svcutil.exe

c# - ¿Es svcutil.exe un reemplazo para xsd.exe?



xml (5)

Sí, svcutil.exe se puede usar como reemplazo de xsd.exe pero parece que tiene problemas para generar colecciones genéricas. svcutil.exe tiene un svcutil.exe 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

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.

Por ejemplo, dado este simple esquema .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 / classes 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: code / dataContractOnly / serializer: 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 ajustar 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?


He probado los mismos comandos en otro esquema, y ​​recibí resultados "basura" similares 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 actualizada: descubrí que muchas de estas matrices genéricas de nodos xml se reemplazaron por tipos fuertes cuando todas las XSD referenciadas se incluyen a 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.


Simplemente crearía tu propio xsd.exe. Lamento haber tenido problemas para pegar pero si copias este 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; } } } } } }

}


Aclaración

La respuesta de Andrew Hare anterior funcionará, pero el comando de ejemplo que jameswelle pegó justo encima de su última sección de código:

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

no funciona porque, como se indica en MSDN , ''. . .los conmutadores / r y / ct para tipos de referencia son para generar contratos de datos. Estos interruptores no funcionan cuando se usa XmlSerializer. ''

HTH.