2009-08-07 3 views
20

Я использую xsd.exe для генерации некоторых классов C# из файла .xsd. Я столкнулся с той же проблемой, что и здесь, и на других сайтах, где xsd.exe генерирует массивы Type [] вместо общих коллекций List для типов в файле .xsd. Некоторые люди предположили, что svcutil.exe можно использовать в качестве замены для xsd.exe, если вы передаете параметр/dataContractOnly в svcutil.exe. Однако кажется, что эти люди ошибаются, потому что svcutil.exe фактически генерирует свойства массива System.Xml.XmlNode [] вместо создания типов на основе схемы в файле .xsd.Является ли svcutil.exe заменой для xsd.exe?

Например, если этот простой 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/классы Example.xsd' генерирует:

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/цель: код/​​dataContractOnly/сериализатору: XmlSerializer/importXmlTypes /collectionType:System.Collections.Generic.List`1 Example.xsd»генерирует:

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. Действительно ли svcutil.exe является заменой для xsd.exe? Полученный результат кажется совсем другим.

  2. На данный момент, похоже, что мне нужно будет использовать xsd.exe для создания классов из моего .xsd-файла, а затем вручную настроить его, чтобы получить его в форме, которую я хочу. Я понимаю, что использование чисто сгенерированного кода было бы идеальным, но мне было интересно, если другие люди используют xsd.exe в качестве отправной точки, а затем работают оттуда или мне нужно вообще рассмотреть другой подход?

  3. Есть обновления к xsd.exe в Visual Studio 2010?

+0

svcutil не предназначен для замены xsd.exe. Чтобы как можно ближе подойти, попробуйте использовать переключатели '/ dataContractOnly' и '/ serializer: XmlSerializer'. –

+0

ServiceUtil путается опцией 'xs: all'. Если ваш XSD должен был использовать 'xs: sequence', svcUtil генерировал бы правильный вывод. Из документов на datacontract serializer и svcUtil: xs: all - Forbidden. http://msdn.microsoft.com/en-us/library/ms733112(v=vs.110).aspx – jessehouwing

+0

Вы можете найти свой ответ на тот же вопрос [здесь] [1] [1 ]: http://stackoverflow.com/a/24557248/1125467 – vivekp

ответ

6

Да, svcutil.exeможет быть использован в качестве замены для xsd.exe, но это звучит, как у вас возникли проблемы при получении обобщенных коллекций, которые будут созданы. svcutil.exe имеет collectionType переключатель, который позволяет указать тип будет использоваться для коллекции:

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

Я добавил пример выше, чтобы показать результат, который сгенерирован. – jameswelle

1

я испытал те же команды на другую схему, анг получил подобные «мусорные» результаты SvcUtil. Таким образом, возможно, это способ заставить его работать как xsd.exe, но пока все, что я видел, гораздо менее полезны.


Обновленный ответ: я обнаружил, что многие из этих общих массивов XML узлов были заменены сильными типами, когда все упомянутые XSD являются принудительно включены. В моем случае у меня есть много файлов xsd, на которые все ссылаются друг на друга, но svcutil, похоже, не включает их. я должен был вместо этого сказать, чтобы использовать * .xsd, чтобы получить их все.

+0

было ли это ответом на вопрос? Это похоже на вопрос. Если это так, вы должны задать отдельный вопрос. –

+0

Я обновил его, но после рассмотрения вопроса больше, я думаю, что мой ответ все еще не применим, поскольку его схема кажется всеобъемлющей, в отличие от тех, с которыми я работаю. –

+1

ни svcutil, ни xsd.exe не будут автоматически ссылаться на включенные файлы. В обоих случаях вы должны сказать им, на какие файлы посмотреть. –

2

Я бы просто создал свой собственный xsd.exe.К сожалению возникают проблемы со вставкой, но если скопировать этот код в ваш основной:

 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: это касается его проблемы? –

4

Разъяснение

ответ Эндрю зайца выше будет работы, но пример команды, которая jameswelle вставили просто выше его последнего раздела кода:

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

не имеет работа т.к., as stated on MSDN, '. , ./r и /ct Коммутаторы для ссылочных типов предназначены для создания контрактов данных. Эти переключатели не работают при использовании XmlSerializer. '

HTH.

Смежные вопросы