Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to approach writing an F# type provider that enforces complex schema?

Just recently I worked with some data for traffic and travel information, that is data in Datex2 format. The project wasn't long and is over now, and I went on as usually and generated a bunch of strongly typed C# classes with xsd.exe tool, did some serializing, light processing and so forth. However, now in hindsight I became to wonder if this would have been a good case for an F# type provider and so to take my first stab on this subject.

With this in mind, how should one approach a situation where there's a complex schema that shouldn't change often? As there isn't a publicly available type provider that would infer types from a schema directly, I guess the options are to:

  • Use the XML type provider.
  • Generate the types with and external tool, xsd.exe in this case -- taking a cue from the WSDL type provider (which uses svcutil.exe).
  • Roll the types by hand (possibly modifying the output of xsd.exe).
  • Generate the types (as in previous bullet)/use the XML Type provider and do constant serializing, deserializing and schema validation in the background.

Then I also started to wonder about the C#-F# story (e.g. generated or erased types) and what if I wanted to modify the types to better check constraints like <xs:element name="ilc" type="D2LogicalModel:TpegIlcPointDescriptor" maxOccurs="3"> in the schema whilst also providing a good developer experience.

Rolling one's own types looks like a rather laborius endavour and the the two last points seemed being the most appealing ones, so taking the route as described here by nos in another SO post. I used System.Xml and System.CodeDom and modified the code to use Microsoft.FSharp.Compiler.CodeDom and FSharpCodeProvider to generate the F# types.

Alas! The generated F# code doesn't compile (even after adding the appropriate referecenses etc.) At this point I thought I could ask some directions.

Question: Is there a recommened, experience backed way to create a type provider to conform to a somewhat complex XML schema (taking Datex2 as a case example) if I would like to enforce constraints as described in a given schema as early as possible in the development cycle?

<edit 2013-12-10: Rune FS is attempting to take a stab on this, see his SO question Getting compile error on provided type.

like image 344
Veksi Avatar asked Nov 16 '13 21:11

Veksi


1 Answers

This is a pretty complex question and I guess there is no simple answer - I think you probably enumerated all the options and also most of their trade-offs. For one-off projects, it does not really make sense to build a specific type provider for just a single purpose, so I think using XML provider or code generation are the only choices. Code generation (when modifying the generated code) is a maintenance nightmare.

As for the XML type provider, we have a work item to add support for XSD (this would be nice community contribution as it is quite stand-alone), so if we had that, then I believe using the XML type provider would be perfect, because you could just pass it the DATEX II schema.

At the moment, F# Data uses erased types (bad for C# interop) but we are actually considering switching to generated types, which would make the provider usable from C# (via small F# project) - so, I think the type providers are the answer here, but they might need a few improvements before they're perfect for your project (but then, F# Data is an open source project and we always welcome contributions :-)).

like image 115
Tomas Petricek Avatar answered Sep 27 '22 23:09

Tomas Petricek