tags:

views:

53

answers:

3

Hi, I'm trying to generate an xs:schema from any .net Type programmatically. I know I could use reflection and generate it by iterating over the public properties, but is there a built in way?

Example:

[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; }
}

Desired Output:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
  <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>
+1  A: 

You can programmatically invoke xsd.exe:

  1. Add xsd.exe as assembly reference.
  2. using XsdTool;
  3. Xsd.Main(new[] { "myassembly.dll", "/type:MyNamespace.MyClass" });

You can also use Reflector to look at the XsdTool.Xsd.ExportSchemas method. It uses the public XmlReflectionImporter, XmlSchemas, XmlSchema XmlSchemaExporter and XmlTypeMapping classes to create a schema from .NET types.

Essentially it does this:

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(...);
}                 ↑

You should be able to customize the output by passing a suitable writer to the XmlSchema.Write method.

dtb
That's interesting, I didn't know you could do that. Not really what I'm looking for. The reason to do it programmatically would be to control the output.
Zachary Yates
I've actually already done that. It's sort of a cluster, I was hoping someone knew a better way.
Zachary Yates
A: 

The XML Schema Definition tool generates XML schema or common language runtime classes from XDR, XML, and XSD files, or from classes in a runtime assembly.

http://msdn.microsoft.com/en-us/library/x6c1kb0s(VS.71).aspx

JBeurer
Running an .exe doesn't count as programmatic.
Zachary Yates
You can always run .exe from your code. ;)
JBeurer
+4  A: 

So this works, I guess it wasn't as ugly as it seemed:

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);

I was still hoping there was a 2 line solution out there, it seems like there should be, thanks for the tip @dtb


EDIT Just for kicks, here's the 2 line version (self deprecating humor)

var typeMapping = new SoapReflectionImporter().ImportTypeMapping(typeof(Person));
new XmlSchemaExporter(new XmlSchemas { new XmlSchema() }).ExportTypeMapping(typeMapping);
Zachary Yates