25

我正在使用 xsd.exe 从 .xsd 文件生成一些 c# 类。我在此处和其他站点上遇到了相同的问题,其中 xsd.exe 为 .xsd 文件中的类型生成 Type[] 数组而不是通用 List 集合。有人建议,如果您将 /dataContractOnly 参数传递给 svcutil.exe,则可以使用 svcutil.exe 作为 xsd.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. Visual Studio 2010 中的 xsd.exe 是否有任何更新?

4

5 回答 5

8

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

svcutil /o:Svc.cs /ct:System.Collections.Generic.List`1 http://example.com
于 2009-08-07T17:11:20.407 回答
7

澄清

安德鲁·黑尔(Andrew Hare)的上述回答起作用,但 jameswelle 粘贴在他最后一段代码上方的示例命令:

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

不起作用因为如 MSDN 所述,'。. . 用于引用类型的/r/ct开关用于生成数据协定。使用 XmlSerializer 时,这些开关不起作用。

HTH。

于 2012-06-28T20:13:30.777 回答
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;
                    }
                }
            }
        }
    }

}

}

于 2011-02-28T05:12:13.780 回答
1

我已经在另一个模式上测试了相同的命令,ang 从 svcutil 收到了类似的“垃圾”结果。所以,这可能是一种让它像 xsd.exe 一样工作的方法,但到目前为止,我所看到的都没有那么有用。


更新的答案:我发现当强制包含所有引用的 XSD 时,许多这些 xml 节点的通用数组被强类型替换。就我而言,我有许多相互引用的 xsd 文件,但 svcutil 似乎不包括它们。我不得不告诉它使用 *.xsd 来获取它们。

于 2010-07-27T23:55:57.793 回答
1

我发现 Xsd2Code 比 xsd.exe 做得更好,完全可以满足您的需要。见这里:http: //xsd2code.codeplex.com/

于 2013-12-03T04:45:33.627 回答