代码之家  ›  专栏  ›  技术社区  ›  Zachary Yates

如何以编程方式从类型生成xml模式?

  •  12
  • Zachary Yates  · 技术社区  · 14 年前

    我试图以编程方式从任何.net类型生成xs:schema。我知道我可以使用反射并通过迭代公共属性来生成它,但是有内置的方法吗?

    例子:

    [Serializable]
    public class Person
    {
        [XmlElement(IsNullable = false)] public string FirstName { get; set; }
        [XmlElement(IsNullable = false)] public string LastName { get; set; }
        [XmlElement(IsNullable = true)] public string PhoneNo { get; set; }
    }
    

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="Person" type="Person" />
      <xs:complexType name="Person">
        <xs:sequence>
          <xs:element minOccurs="0" maxOccurs="1" form="unqualified" name="FirstName" type="xs:string" />
          <xs:element minOccurs="0" maxOccurs="1" form="unqualified" name="LastName" type="xs:string" />
          <xs:element minOccurs="0" maxOccurs="1" form="unqualified" name="PhoneNo" type="xs:string" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
    
    5 回复  |  直到 14 年前
        1
  •  14
  •   Community CDub    7 年前

    我找到了 accepted answer [XmlEnum(Name="Foo")]

    我相信这是正确的方法(考虑到你的使用) XmlSerializer )也很简单:

    var schemas = new XmlSchemas();
    var exporter = new XmlSchemaExporter(schemas);
    var mapping = new XmlReflectionImporter().ImportTypeMapping(typeof(Person));
    exporter.ExportTypeMapping(mapping);
    var schemaWriter = new StringWriter();
    foreach (XmlSchema schema in schemas)
    {
        schema.Write(schemaWriter);
    }
    return schemaWriter.ToString();
    

    http://blogs.msdn.com/b/youssefm/archive/2010/05/13/using-xml-schema-import-and-export-for-xmlserializer.aspx

        2
  •  10
  •   Zachary Yates    14 年前

    所以这是可行的,我猜它并不像看上去那么难看:

    var soapReflectionImporter = new SoapReflectionImporter();
    var xmlTypeMapping = soapReflectionImporter.ImportTypeMapping(typeof(Person));
    var xmlSchemas = new XmlSchemas();
    var xmlSchema = new XmlSchema();
    xmlSchemas.Add(xmlSchema);
    var xmlSchemaExporter = new XmlSchemaExporter(xmlSchemas);
    xmlSchemaExporter.ExportTypeMapping(xmlTypeMapping);
    

    我还是希望有一个2线的解决方案,似乎应该有,谢谢提示@dtb


    编辑 只是为了好玩,这里有两行版本(自嘲幽默)

    var typeMapping = new SoapReflectionImporter().ImportTypeMapping(typeof(Person));
    new XmlSchemaExporter(new XmlSchemas { new XmlSchema() }).ExportTypeMapping(typeMapping);
    
        3
  •  6
  •   dtb    14 年前

    您可以通过编程方式调用 xsd.exe

    1. 添加 作为程序集参考。
    2. using XsdTool;
    3. Xsd.Main(new[] { "myassembly.dll", "/type:MyNamespace.MyClass" });

    XsdTool.Xsd.ExportSchemas 方法。它利用公众 XmlReflectionImporter , XmlSchemas , XmlSchema XmlSchemaExporter XmlTypeMapping 类从.NET类型创建架构。

    本质上是这样的:

    var importer = new XmlReflectionImporter();
    var schemas = new XmlSchemas();
    var exporter = new XmlSchemaExporter(schemas);
    
    var xmlTypeMapping = importer.ImportTypeMapping(typeof(Person));
    exporter.ExportTypeMapping(xmlTypeMapping);
    
    schemas.Compile(..., false);
    
    for (var i = 0; i < schemas.Count; i++)
    {
        var schema = schemas[i];
        schema.Write(...);
    }                 ↑
    

    您应该能够通过将合适的writer传递给 XmlSchema.Write

        4
  •  1
  •   Mrchief    11 年前

    我相信这就是你想要的: Writing your own XSD.exe

    以上借款代码:

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Xml.Schema;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    
    using Microsoft.CSharp;
    
    using NUnit.Framework;
    
    namespace XmlSchemaImporterTest
    {
      [TestFixture]
      public class XsdToClassTests
      {
          // Test for XmlSchemaImporter
          [Test]
          public void XsdToClassTest()
          {
              // identify the path to the xsd
              string xsdFileName = "Account.xsd";
              string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
              string xsdPath = Path.Combine(path, xsdFileName);
    
              // load the xsd
              XmlSchema xsd;
              using(FileStream stream = new FileStream(xsdPath, FileMode.Open, FileAccess.Read))
              {
                  xsd = XmlSchema.Read(stream, null);
              }
              Console.WriteLine("xsd.IsCompiled {0}", xsd.IsCompiled);
    
              XmlSchemas xsds = new XmlSchemas();
              xsds.Add(xsd);
              xsds.Compile(null, true);
              XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds);
    
              // create the codedom
              CodeNamespace codeNamespace = new CodeNamespace("Generated");
              XmlCodeExporter codeExporter = new XmlCodeExporter(codeNamespace);
    
              List maps = new List();
              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);
              }
    
              RemoveAttributes(codeNamespace);
    
              // Check for invalid characters in identifiers
              CodeGenerator.ValidateIdentifiers(codeNamespace);
    
              // output the C# code
              CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    
              using(StringWriter writer = new StringWriter())
              {
                  codeProvider.GenerateCodeFromNamespace(codeNamespace, writer, new CodeGeneratorOptions());
                  Console.WriteLine(writer.GetStringBuilder().ToString());
              }
    
              Console.ReadLine();
          }
    
          // Remove all the attributes from each type in the CodeNamespace, except
          // System.Xml.Serialization.XmlTypeAttribute
          private void RemoveAttributes(CodeNamespace codeNamespace)
          {
              foreach(CodeTypeDeclaration codeType in codeNamespace.Types)
              {
                  CodeAttributeDeclaration xmlTypeAttribute = null;
                  foreach(CodeAttributeDeclaration codeAttribute in codeType.CustomAttributes)
                  {
                      Console.WriteLine(codeAttribute.Name);
                      if(codeAttribute.Name == "System.Xml.Serialization.XmlTypeAttribute")
                      {
                          xmlTypeAttribute = codeAttribute;
                      }
                  }
                  codeType.CustomAttributes.Clear();
                  if(xmlTypeAttribute != null)
                  {
                      codeType.CustomAttributes.Add(xmlTypeAttribute);
                  }
              }
          }
      }
    }