svcutil。替换xsd.exe?

时间:2022-10-12 17:18:12

I am using xsd.exe to generate some c# classes from a .xsd file. I ran into the same issue that is covered here and on other sites where xsd.exe generates Type[] arrays instead of generic List collections for types in the .xsd file. Some people have suggested that svcutil.exe can be used as a replacement for xsd.exe if you pass the /dataContractOnly parameter to svcutil.exe. However, it seems like those people are mistaken because svcutil.exe actually generates System.Xml.XmlNode[] array properties instead of creating types based on the schema in the .xsd file.

我使用xsd。exe从.xsd文件中生成一些c#类。我遇到了同样的问题,在这里和其他一些xsd。exe生成类型[]数组,而不是.xsd文件中类型的泛型列表集合。有些人建议svcutil。exe可以作为xsd的替换。如果您将/dataContractOnly参数传递给svcutil.exe,则为exe。然而,这些人似乎错了,因为svcutil。exe实际上生成System.Xml。XmlNode[]数组属性,而不是基于.xsd文件中的模式创建类型。

For example, given this simple .xsd schema:

例如,给定这个简单的.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' generates:

xsd。exe /类的例子。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' generates:

“svcutil。exe /target:code /dataContractOnly /serializer:XmlSerializer /importXmlTypes /collectionType:System.Collections.Generic. generic。清单1的例子。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. Is svcutil.exe really supposed to be a replacement for xsd.exe? The output generated seems to be quite different.

    svcutil。exe真的应该是xsd。exe的替代品吗?所产生的输出似乎完全不同。

  2. At this point, it looks like I will have to use xsd.exe to create classes from my .xsd file and then manually tweak the the code to get it in the form I want. I realize that using purely generated code would be ideal, but I was wondering if other people are using xsd.exe as a starting point and then working from there or if I need to consider another approach altogether?

    此时,看起来我必须使用xsd。exe从我的.xsd文件中创建类,然后手动调整代码以获得我想要的表单。我意识到使用纯生成的代码是理想的,但是我想知道其他人是否在使用xsd。exe作为起点,然后从那里开始工作,或者如果我需要考虑另一种方法?

  3. Are there any updates to xsd.exe in Visual Studio 2010?

    xsd是否有任何更新。在Visual Studio 2010中?

5 个解决方案

#1


6  

Yes, svcutil.exe can be used as a replacement for xsd.exe but it sounds like you are having trouble getting generic collections to be generated. svcutil.exe has a collectionType switch that allows you to specify the type to be used for a collection:

是的,svcutil。exe可以作为xsd的替换。但是听起来您在生成泛型集合时遇到了麻烦。svcutil。exe有一个集合类型开关,允许您指定用于集合的类型:

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

#2


4  

Clarification

澄清

Andrew Hare's answer above will work, but the example command that jameswelle pasted just above his last section of code:

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

does not work because, as stated on MSDN, '. . .the /r and /ct switches for referencing types are for generating data contracts. These switches do not work when using XmlSerializer.'

Andrew Hare上面的答案是可行的,但是jameswelle粘贴的示例命令刚好在他的最后一段代码之上:svcutil。exe /target:code /dataContractOnly /serializer:XmlSerializer /importXmlTypes /collectionType:System.Collections.Generic. generic。清单1的例子。xsd并不起作用,因为正如MSDN上所述,用于引用类型的/r和/ct交换机用于生成数据契约。在使用XmlSerializer时,这些开关不工作。

HTH.

HTH。

#3


2  

I would just create your own xsd.exe. Sorry having trouble pasting but if you copy this code into your main:

我只需要创建你自己的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;
                    }
                }
            }
        }
    }

}

}

}

#4


1  

I have tested the same commands on another schema, ang received similar "junk" results from svcutil. So, the might be a way to make it work like xsd.exe, but so far all Ive seen are far less useful ones.

我在另一个模式上测试了相同的命令,ang从svcutil获得了类似的“垃圾”结果。因此,这可能是一种使它像xsd那样工作的方法。但是到目前为止,我所看到的都不是那么有用。


Updated answer: I found that many of these generic arrays of xml nodes were replaced by strong types when all the referenced XSD's are forcibly included. In my case, i have many xsd files all referenced by each other, but svcutil doesnt seem to include them. i had to instead tell it to use *.xsd to get them all.

更新的答案:我发现当所有引用的XSD都被强制包含时,许多xml节点的通用数组被强类型替换。在我的例子中,我有许多xsd文件都是相互引用的,但是svcutil似乎没有包含它们。我不得不告诉它使用*。将它们全部获取。

#5


1  

I have found Xsd2Code to be much better than xsd.exe does does exactly what you need. See here: http://xsd2code.codeplex.com/

我发现Xsd2Code比xsd好多了。exe完成所需的工作。在这里看到的:http://xsd2code.codeplex.com/

#1


6  

Yes, svcutil.exe can be used as a replacement for xsd.exe but it sounds like you are having trouble getting generic collections to be generated. svcutil.exe has a collectionType switch that allows you to specify the type to be used for a collection:

是的,svcutil。exe可以作为xsd的替换。但是听起来您在生成泛型集合时遇到了麻烦。svcutil。exe有一个集合类型开关,允许您指定用于集合的类型:

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

#2


4  

Clarification

澄清

Andrew Hare's answer above will work, but the example command that jameswelle pasted just above his last section of code:

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

does not work because, as stated on MSDN, '. . .the /r and /ct switches for referencing types are for generating data contracts. These switches do not work when using XmlSerializer.'

Andrew Hare上面的答案是可行的,但是jameswelle粘贴的示例命令刚好在他的最后一段代码之上:svcutil。exe /target:code /dataContractOnly /serializer:XmlSerializer /importXmlTypes /collectionType:System.Collections.Generic. generic。清单1的例子。xsd并不起作用,因为正如MSDN上所述,用于引用类型的/r和/ct交换机用于生成数据契约。在使用XmlSerializer时,这些开关不工作。

HTH.

HTH。

#3


2  

I would just create your own xsd.exe. Sorry having trouble pasting but if you copy this code into your main:

我只需要创建你自己的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;
                    }
                }
            }
        }
    }

}

}

}

#4


1  

I have tested the same commands on another schema, ang received similar "junk" results from svcutil. So, the might be a way to make it work like xsd.exe, but so far all Ive seen are far less useful ones.

我在另一个模式上测试了相同的命令,ang从svcutil获得了类似的“垃圾”结果。因此,这可能是一种使它像xsd那样工作的方法。但是到目前为止,我所看到的都不是那么有用。


Updated answer: I found that many of these generic arrays of xml nodes were replaced by strong types when all the referenced XSD's are forcibly included. In my case, i have many xsd files all referenced by each other, but svcutil doesnt seem to include them. i had to instead tell it to use *.xsd to get them all.

更新的答案:我发现当所有引用的XSD都被强制包含时,许多xml节点的通用数组被强类型替换。在我的例子中,我有许多xsd文件都是相互引用的,但是svcutil似乎没有包含它们。我不得不告诉它使用*。将它们全部获取。

#5


1  

I have found Xsd2Code to be much better than xsd.exe does does exactly what you need. See here: http://xsd2code.codeplex.com/

我发现Xsd2Code比xsd好多了。exe完成所需的工作。在这里看到的:http://xsd2code.codeplex.com/