Generating C# classes from FpML Schema

by 26. December 2008 05:26

This problem recently came up while discussing a project that will use FpML documents. FpML is an evolving standard that aims to be the industry standard protocol for complex financial products. Its an extensive project with a good deal of support from major players and a sharp talent pool behind it.

I’ll try to explain how code generation facilities built into the .Net framework can provide us with a basic usable class library that encapsulates the FpML protocol.

We begin by downloading the relevant schemas from the FpML website (requires free registration) and extracting them to a local folder (C:\FpML).

Then we fire up Visual Studio and create a new Console Application. At this point you maybe wondering if it wouldn’t be simpler to just use XSD.EXE for the code generation. Unfortunately XSD.EXE has difficulty resolving external schemas.

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
using Microsoft.CSharp;

namespace ConsoleApplication1
{
    internal class Program
    {
        public const string rootFolder = @"C:\FpML\xml\";

        private static void Main(string[] args)
        {
            XmlSchema rootSchema = GetSchemaFromFile("fpml-main-4-2.xsd");

            var schemaSet = new List<XmlSchemaExternal>();

            ExtractIncludes(rootSchema, ref schemaSet);

            var schemas = new XmlSchemas { rootSchema };

            schemaSet.ForEach(schemaExternal => schemas.Add(GetSchemaFromFile(schemaExternal.SchemaLocation)));

            schemas.Compile(null, true);

            var xmlSchemaImporter = new XmlSchemaImporter(schemas);

            var codeNamespace = new CodeNamespace("Hosca.FpML4_2");
            var xmlCodeExporter = new XmlCodeExporter(codeNamespace);

            var xmlTypeMappings = new List<XmlTypeMapping>();

            foreach (XmlSchemaType schemaType in rootSchema.SchemaTypes.Values)
                xmlTypeMappings.Add(xmlSchemaImporter.ImportSchemaType(schemaType.QualifiedName));
            foreach (XmlSchemaElement schemaElement in rootSchema.Elements.Values)
                xmlTypeMappings.Add(xmlSchemaImporter.ImportTypeMapping(schemaElement.QualifiedName));

            xmlTypeMappings.ForEach(xmlCodeExporter.ExportTypeMapping);

            CodeGenerator.ValidateIdentifiers(codeNamespace);

            foreach (CodeTypeDeclaration codeTypeDeclaration in codeNamespace.Types)
            {
                for (int i = codeTypeDeclaration.CustomAttributes.Count - 1; i >= 0; i--)
                {
                    CodeAttributeDeclaration cad = codeTypeDeclaration.CustomAttributes[i];
                    if (cad.Name == "System.CodeDom.Compiler.GeneratedCodeAttribute")
                        codeTypeDeclaration.CustomAttributes.RemoveAt(i);
                }
            }

            using (var writer = new StringWriter())
            {
                new CSharpCodeProvider().GenerateCodeFromNamespace(codeNamespace, writer, new CodeGeneratorOptions());

                //Console.WriteLine(writer.GetStringBuilder().ToString());

                File.WriteAllText(Path.Combine(rootFolder, "FpML4_2.Generated.cs"), writer.GetStringBuilder().ToString());
            }

            Console.ReadLine();
        }

        private static XmlSchema GetSchemaFromFile(string fileName)
        {
            using (var fs = new FileStream(Path.Combine(rootFolder, fileName), FileMode.Open))
                return XmlSchema.Read(fs, null);
        }

        private static void ExtractIncludes(XmlSchema xmlSchema, ref List<XmlSchemaExternal> schemaList)
        {
            foreach (XmlSchemaExternal include in xmlSchema.Includes)
            {
                if (!schemaList.Select(s => s.SchemaLocation).Contains(include.SchemaLocation))
                    schemaList.Add(include);

                if (include.Schema == null)
                {
                    XmlSchema schema = GetSchemaFromFile(include.SchemaLocation);

                    ExtractIncludes(schema, ref schemaList);
                }
                else
                    ExtractIncludes(include.Schema, ref schemaList);
            }
        }
    }
}

Running this generates the following code:

FpML4_2.Generated.cs (1.10 mb)

Comments

1/28/2010 10:11:19 PM #

James McMorrough

That has got to be one of the most amazing bits of code I've ever encountered.

James McMorrough United Kingdom | Reply

2/4/2010 7:06:20 PM #

xbox купить

hat has got to be one of the most amazing bits of code I've ever encountered.

xbox купить Russia | Reply

2/18/2010 11:15:58 PM #

this website

This was a really great post to read! I thoroughly enjoyed it. Maybe when I get a chance to return I'll read some more.

this website New Zealand | Reply

2/19/2010 2:15:45 AM #

Bo Yu

Hi, Erhan:

I used your program to generate C# classes but I still got a lot of problems when deserialize from XML to C# objects. Some sample errors here:
Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'FpML.RoutingId[]' to 'FpML.RoutingId'
error CS0030: Cannot convert type 'FpML.SettlementPeriodsReference[]' to 'FpML.SettlementPeriodsReference'
error CS0030: Cannot convert type 'FpML.SettlementPeriodsReference[]' to 'FpML.SettlementPeriodsReference'
error CS0029: Cannot implicitly convert type 'FpML.RoutingId' to 'FpML.RoutingId[]'
error CS0029: Cannot implicitly convert type 'FpML.SettlementPeriodsReference' to 'FpML.SettlementPeriodsReference[]'
error CS0029: Cannot implicitly convert type 'FpML.SettlementPeriodsReference' to 'FpML.SettlementPeriodsReference[]'

Do you have any solutions for this kind of problems. I know a guy stated if I put all the schema files into one single one the problem would go away even using XSD.exe.

Any help is highly appreciated.

Bo Yu United States | Reply

2/22/2010 1:25:51 AM #

Kris

This worked like a charm. Very nice.

Kris United States | Reply

2/26/2010 4:25:22 PM #

Fatcow Coupon

Should I get a Virtual Private Server? Currently I am using ixwebhosting but they keep shutting me down due to high server load. Im getting about 3,000 UV a day. What brand should I get?

Fatcow Coupon United States | Reply

3/2/2010 2:01:38 PM #

wow mobiles

WoW Mobile is awesome! I get free mobile service with t-mobile because I refered 3 people to wow. You can too!

wow mobiles United States | Reply

3/2/2010 4:13:21 PM #

wow mobiles

WoW Mobile is awesome! I get free mobile service with t-mobile because I refered 3 people to wow. You can too!

wow mobiles United States | Reply

3/3/2010 2:59:14 AM #

Bobby

Hey there, are you having issues with your hosting? I needed to refresh the page about four times to your site load. You might want to change hosts, or could the problem be from me?

-Bobby

Bobby United States | Reply

3/5/2010 1:09:02 AM #

Vedeževanje preko interneta

Amazing blog! Its not frequently that I comment but I felt you deserve it

Vedeževanje preko interneta Slovenia | Reply

3/9/2010 1:10:58 AM #

pingback

Pingback from mdavey.wordpress.com

F#: Modelling An IRS Trade Using FpML 5.0 « Tales from a Trading Desk

mdavey.wordpress.com | Reply

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading