How to convert a choice type automatically provided by XmlProvider<...>.DomainTypes into an enumeration in F#?

StackOverflow https://stackoverflow.com/questions/22114677

Question

Let's say I have the following XML:

<?xml version="1.0" encoding="UTF-16"?>
<iAmConfused>
    <helpMe feeling="anger" strength="100" mapping="1-1" />
    <helpMe feeling="frustration" strength="15" mapping="1-n" />
    <helpMe feeling="helplessness" strength="365" mapping="1-1" />
    <helpMe feeling="despair" strength="-1" mapping="1-n" />
</iAmConfused>

And want to transform it to an F# Map:

open System.Xml
open System.Xml.Linq
open FSharp.Data

type mappingType =
    | oneToOneMapping = 00
    | oneToManyMapping = 01

type helpMe = {
    strength : int;
    mapping : mappingType}

type iAmConfusedXmlType = XmlProvider<"""<?xml version="1.0" encoding="UTF-16"?><iAmConfused><helpMe feeling="anger" strength="100" mapping="1-1" /><helpMe feeling="frustration" strength="15" mapping="1-n" /><helpMe feeling="helplessness" strength="365" mapping="1-1" /><helpMe feeling="despair" strength="-1" mapping="1-n" /></iAmConfused>""">

let iAmConfusedXml = iAmConfusedXmlType.Parse("""<?xml version="1.0" encoding="UTF-16"?><iAmConfused><helpMe feeling="anger" strength="100" mapping="1-1" /><helpMe feeling="frustration" strength="15" mapping="1-n" /><helpMe feeling="helplessness" strength="365" mapping="1-1" /><helpMe feeling="despair" strength="-1" mapping="1-n" /></iAmConfused>""")

let iWantThisMap =
    iAmConfusedXml.GetHelpMes()
    |> Seq.map (fun e -> e.Feeling, {
        strength = e.Strength;
        mapping = ???})
    |> Map.ofSeq

XmlProvider correctly infers the type of XML attribute mapping to be XmlProvider<...>.DomainTypes.MappingChoice. However, I can't find a way to convert this type to mappingType.

First I tried to convert XML attribute mapping to string in the hopes of then converting it to enumeration mappingType, but even that proves to be too difficult for me...

Rewriting type helpMe in the above code:

type helpMe = {
    strength : int;
    mapping : string}

Then substituting ??? to

string e.Strength

Gives me "Some(1-1)" or "Some(1-n)" for helpMe.mapping which is not what I want.
If I try to substitute ??? to

string (defaultArg e.Mapping "")

Then FSI rightfully complains:

test.fs(165,38): error FS0001: This expression was expected to have type
    'a option    
but here has type
    XmlProvider<...>.DomainTypes.MappingChoice
Was it helpful?

Solution

Well, to convert from a string to mappingType, you can define a little helper function:

let convert m =
    match m with
    | "1-1" -> mappingType.oneToOneMapping
    | _ -> mappingType.oneToManyMapping

Which will enable you to write your projection like:

let iWantThisMap =
    iAmConfusedXml.GetHelpMes()
    |> Seq.map (fun e -> e.Feeling, {
        strength = e.Strength;
        mapping = (e.Mapping.Value |> convert) })
    |> Map.ofSeq

Now, there's a bit of cheating here because it's simply calling e.Mapping.Value. This might throw an exception if e.Mapping is None, but it works given the data provided here, because e.Mapping always has a value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top