Является ли svcutil.exe заменой xsd.exe? - PullRequest
21 голосов
/ 07 августа 2009

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

Например, для этой простой схемы .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' создает:

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' создает:

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?

Ответы [ 5 ]

6 голосов
/ 07 августа 2009

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

svcutil /o:Svc.cs /ct:System.Collections.Generic.List`1 http://example.com
4 голосов
/ 29 июня 2012

Разъяснение

Ответ Эндрю Хэра выше будет работать, но пример команды, которую jameswelle вставил чуть выше своего последнего раздела кода:

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

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

НТН.

2 голосов
/ 28 февраля 2011

Я бы просто создал свой собственный 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;
                    }
                }
            }
        }
    }

}

}

1 голос
/ 03 декабря 2013

Я обнаружил, что Xsd2Code намного лучше, чем xsd.exe делает именно то, что вам нужно. Посмотреть здесь: http://xsd2code.codeplex.com/

1 голос
/ 28 июля 2010

Я тестировал те же команды на другой схеме, и анг получал аналогичные "нежелательные" результаты от svcutil. Так что, возможно, можно заставить его работать как xsd.exe, но пока все, что я видел, гораздо менее полезны.


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

...