【问题标题】:Is svcutil.exe a replacement for xsd.exe?svcutil.exe 是 xsd.exe 的替代品吗?
【发布时间】:2025-11-29 19:45:01
【问题描述】:

我正在使用 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 是否有任何更新?

【问题讨论】:

  • svcutil 不是 xsd.exe 的替代品。要尽可能接近,请尝试使用 /dataContractOnly 和 '/serializer:XmlSerializer` 开关。
  • ServiceUtil 被 xs:all 选项弄糊涂了。如果您的 XSD 使用 xs:sequence svcUtil 将生成正确的输出。来自 datacontract 序列化程序和 svcUtil 的文档:xs:all - Forbidden。 msdn.microsoft.com/en-us/library/ms733112(v=vs.110).aspx
  • 你可以找到我对同一个问题的回答 [这里][1] [1]:*.com/a/24557248/1125467

标签: c# xml xsd xsd.exe svcutil.exe


【解决方案1】:

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

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

【讨论】:

  • 我在上面添加了一个示例来显示生成的输出。
【解决方案2】:

澄清

Andrew Hare 上面的答案起作用,但 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。

【讨论】:

    【解决方案3】:

    我只想创建您自己的 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】:

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


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

      【讨论】:

      • 这是为了回答这个问题吗?这听起来像是一个问题本身。如果是这样,您应该提出一个单独的问题。
      • 我更新了它,但在仔细检查了这个问题之后,我认为我的答案仍然不适用,因为他的架构似乎是包罗万象的,不像我正在使用的架构。
      • svcutil 和 xsd.exe 都不会自动引用包含的文件。在这两种情况下,您都必须告诉他们要查看哪些文件。
      • 不正确 - XSD.exe 将引入 xsd “包含”。我一直在使用这个功能。 SvcUtil 显然忽略了它们。
      【解决方案5】:

      我发现 Xsd2Code 比 xsd.exe 好得多,它完全可以满足您的需求。看这里: http://xsd2code.codeplex.com/

      【讨论】: