2009-08-07 7 views
20

J'utilise xsd.exe pour générer des classes C# à partir d'un fichier .xsd. J'ai rencontré le même problème qui est couvert ici et sur d'autres sites où xsd.exe génère des tableaux Type [] à la place des collections de listes génériques pour les types dans le fichier .xsd. Certaines personnes ont suggéré que svcutil.exe peut être utilisé en remplacement de xsd.exe si vous transmettez le paramètre/dataContractOnly à svcutil.exe. Cependant, il semble que ces personnes se trompent car svcutil.exe génère réellement les propriétés du tableau System.Xml.XmlNode [] au lieu de créer des types basés sur le schéma du fichier .xsd.svcutil.exe est-il un remplacement de xsd.exe?

Par exemple, étant donné ce simple schéma 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' génère:

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/sérialiseur: XmlSerializer/importXmlTypes /collectionType:System.Collections.Generic.List`1 Example.xsd » génère:

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. Est-ce que svcutil.exe est vraiment censé être un remplacement de xsd.exe? La sortie générée semble être très différente. À ce stade, il semble que je devrais utiliser xsd.exe pour créer des classes à partir de mon fichier .xsd, puis modifier manuellement le code pour l'obtenir dans la forme que je veux. Je me rends compte que l'utilisation de code purement généré serait idéal, mais je me demandais si d'autres personnes utilisaient xsd.exe comme point de départ et travaillaient à partir de là ou si j'avais besoin d'envisager une autre approche?

  2. Existe-t-il des mises à jour de xsd.exe dans Visual Studio 2010?

+0

svcutil n'était pas destiné à remplacer xsd.exe. Pour vous rapprocher le plus possible, essayez d'utiliser les options '/ dataContractOnly' et '/ serializer: XmlSerializer'. –

+0

ServiceUtil est confus par l'option 'xs: all'. Si votre XSD utilisait 'xs: sequence' svcUtil générerait la sortie appropriée. À partir des documents sur le sérialiseur datacontract et svcUtil: xs: all - Interdit. http://msdn.microsoft.com/en-us/library/ms733112(v=vs.110).aspx – jessehouwing

+0

Vous pouvez trouver ma réponse à la même question [ici] [1] [1 ]: http://stackoverflow.com/a/24557248/1125467 – vivekp

Répondre

6

Oui, svcutil.exepeut être utilisé pour remplacer xsd.exe, mais il semble que vous éprouvez des difficultés à obtenir des collections génériques à générer. svcutil.exe a un interrupteur collectionType qui vous permet de spécifier le type à utiliser pour une collection:

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

J'ai ajouté un exemple ci-dessus pour montrer la sortie qui est générée. – jameswelle

1

J'ai testé les mêmes commandes sur un autre schéma, ang a reçu des résultats similaires « junk » de svcutil. Donc, le peut être un moyen de le faire fonctionner comme xsd.exe, mais jusqu'à présent, tout ce que j'ai vu sont beaucoup moins utiles.


réponse Mise à jour: Je trouve que beaucoup de ces tableaux génériques de noeuds XML ont été remplacés par de forts types lorsque toutes les années XSD sont référencés de force inclus. Dans mon cas, j'ai beaucoup de fichiers xsd tous référencés les uns par les autres, mais svcutil ne semble pas les inclure. Je devais plutôt lui dire d'utiliser * .xsd pour les obtenir tous.

+0

était-ce censé être une réponse à la question? Cela ressemble à une question en soi. Si oui, vous devriez poser une question distincte. –

+0

Je l'ai mis à jour, mais après avoir passé en revue la question plus, je pense que ma réponse n'est toujours pas applicable car son schéma semble être tout compris, contrairement à ceux avec lesquels je travaille. –

+1

ni svcutil ni xsd.exe ne référencera automatiquement les fichiers inclus. Dans les deux cas, vous devez leur indiquer quels fichiers regarder. –

2

Je voudrais juste créer votre propre xsd.exe.Désolé d'avoir du mal à coller, mais si vous copiez ce code dans votre principale:

 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: est-ce que cela règle son problème? –

4

Précision

réponse Andrew Hare au-dessus travaillera, mais la commande exemple que jameswelle collé juste au-dessus de sa dernière section de code:

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

ne pas travail parce que, as stated on MSDN, '. . .les /r et /ct commutateurs pour les types de référence sont pour générer des contrats de données. Ces commutateurs ne fonctionnent pas avec XmlSerializer. '

HTH.

Questions connexes