I'm trying to build a dynamic type/class builder for C# using F#, from the following XML
<config target="string">
<protocol>string</protocol>
<about_path>string</about_path>
<about_content>
<name_path>string</name_path>
<id_path>string</id_path>
<version_path>string</version_path>
</about_content>
</config>
Using the code below I can parse the sample just fine
module XmlParser =
open FSharp.Data
open System.Globalization
open FSharp.Data.Runtime.BaseTypes
open System.Xml.Linq
[<Literal>]
let targetSchema = "<config target=\"string\">
<protocol>string</protocol>
<about_path>string</about_path>
<about_content>
<name_path>string</name_path>
<id_path>string</id_path>
<version_path>string</version_path>
</about_content>
</config>"
type Configuration = XmlProvider<targetSchema>
The problem now is that I can't get my head around retrieving the inner parts of the about_content
tag.
After parsing the actual xml using
let parsedValue = Configuration.Parse(xmlIn)
I've tried to get my head around the recursion handling in F# but am stuck at the non-working code that looks like this (e
would be parsedValue.XElement
)
let rec flatten ( e : System.Xml.Linq.XElement) (out:List<string>) =
if e.HasElements
then for inner in e.Elements -> flatten(inner)
else e.Name.LocalName
What I would need is a hint on how to gather the e.Name.LocalName
values into a sequence/List as a result of the recursion. I could also live with having a list of XElement
s at the end.
The function
flatten
needs to return a sequence, not a single thing.For elements with subelements, you need to call
flatten
for each, then concat all results:(note that
XElement.Elements
is a method, not a property; therefore, you need to add()
to call it)For a single element, just return its name wrapped in a single-element sequence:
Putting it all together:
(also note that I have removed your
out
parameter, which, I assume, was meant to be not a parameter, but an attempt to declare the function's return type; it can be omitted; for reference, function return type in F# is declared after the function's signature with a colon, e.g.let f (x:int) : int = x + 5
)If you prefer a more imperative-looking style, you can use the
seq
computation expression.yield
will yield a single element, whileyield!
will have the effect of yielding each element of another sequence: