2009-08-07 9 views
20

Ich verwende xsd.exe, um einige C# -Klassen aus einer .xsd-Datei zu generieren. Ich stieß auf das gleiche Problem, das hier und auf anderen Websites behandelt wird, wo xsd.exe Typ [] -Arrays statt generische Auflistung Auflistungen für Typen in der XSD-Datei generiert. Einige Leute haben vorgeschlagen, dass svcutil.exe als Ersatz für xsd.exe verwendet werden kann, wenn Sie den Parameter/dataContractOnly an svcutil.exe übergeben. Es scheint jedoch so, als ob diese Personen falsch sind, da svcutil.exe tatsächlich System.Xml.XmlNode [] -Arrayeigenschaften generiert, anstatt Typen basierend auf dem Schema in der XSD-Datei zu erstellen.Ist svcutil.exe ein Ersatz für xsd.exe?

Zum Beispiel angesichts dieser einfachen 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/Klassen Example.xsd' erzeugt:

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‘erzeugt:

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. Ist svcutil.exe wirklich ein Ersatz für xsd.exe? Die erzeugte Ausgabe scheint ganz anders zu sein.

  2. An dieser Stelle sieht es so aus, als müsste ich xsd.exe verwenden, um Klassen aus meiner .xsd-Datei zu erstellen, und dann den Code manuell anpassen, um ihn in der von mir gewünschten Form zu erhalten. Ich weiß, dass die Verwendung von rein generiertem Code ideal wäre, aber ich frage mich, ob andere Leute xsd.exe als Ausgangspunkt verwenden und dann von dort aus arbeiten oder ob ich einen anderen Ansatz insgesamt in Betracht ziehen muss?

  3. Gibt es Updates für xsd.exe in Visual Studio 2010?

+0

svcutil war nicht als Ersatz für xsd.exe gedacht. Um so nahe wie möglich zu kommen, versuchen Sie es mit den Schaltern '/ dataContractOnly' und '/ serializer: XmlSerializer'. –

+0

ServiceUtil wird durch die Option "xs: all" verwirrt. Wenn Ihr XSD 'xs: sequence 'verwenden würde, würde svcUtil die korrekte Ausgabe erzeugen. Aus den Docs auf dem DataContract-Serializer und SVCUtil: xs: all - Forbidden. http://msdn.microsoft.com/en-us/library/ms733112(v=vs.110).aspx – jessehouwing

+0

Sie können meine Antwort auf die gleiche Frage [hier] [1] [1 finden ]: http://stackoverflow.com/a/24557248/1125467 – vivekp

Antwort

6

Ja, svcutil.exekann für xsd.exe als Ersatz verwendet werden, aber es klingt wie Sie Mühe, generische Sammlungen erzeugt werden müssen. svcutil.exe hat einen collectionType Schalter, der die Art angeben können, für eine Sammlung verwendet werden:

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

Ich habe oben ein Beispiel hinzugefügt, um die Ausgabe anzuzeigen, die generiert wird. – jameswelle

1

ich die gleichen Befehle auf einem anderen Schema getestet haben, ang ähnlich „Junk“ Ergebnisse von svcutil erhalten. Also, das könnte eine Möglichkeit sein, es wie xsd.exe funktionieren zu lassen, aber bisher sind alle, die ich gesehen habe, weit weniger nützlich.


Aktualisiert Antwort: Ich fand, dass durch starke Typen ersetzt viele dieser generischen Arrays von XML-Knoten wurden, wenn alle referenzierten XSD des gewaltsam enthalten sind. In meinem Fall habe ich viele xsd-Dateien, die alle von einander referenziert werden, aber Svcutil scheint sie nicht zu enthalten. Ich musste stattdessen sagen, dass ich * .xsd verwenden soll, um sie alle zu bekommen.

+0

sollte dies eine Antwort auf die Frage sein? Es klingt wie eine Frage an sich. Wenn ja, sollten Sie eine separate Frage stellen. –

+0

Ich habe es aktualisiert, aber nachdem ich die Frage noch einmal durchgelesen habe, denke ich, dass meine Antwort immer noch nicht anwendbar ist, da sein Schema allem Anschein nach allumfassend ist, im Gegensatz zu denen, mit denen ich arbeite. –

+1

weder svcutil noch xsd.exe wird automatisch auf die enthaltenen Dateien verweisen. In beiden Fällen müssen Sie ihnen sagen, welche Dateien Sie ansehen sollen. –

2

Ich würde nur Ihre eigene xsd.exe erstellen.Leider haben Probleme einfügen, aber wenn Sie kopieren Sie diesen Code in Ihre Haupt:

 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: Wird damit auf sein Problem eingegangen? –

4

Klärung

Andrew Hares Antwort oben wird Arbeit, aber das Beispiel Befehl, der gerade eingefügt jameswelle über seinem letzten Codeabschnitt:

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

tut nicht arbeiten weil, as stated on MSDN, '. . .die /r und /ct Switches für Referenzierungsarten dienen zum Generieren von Datenverträgen. Diese Schalter funktionieren nicht, wenn Sie XmlSerializer verwenden.

HTH.