Reputation: 819
Within a sample xml file for the F#-Data type provider, I have elements that are optional, like so:
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<OptionalElement> ... </OptionalElement>
<AnotherElement> ... </AnotherElement>
</RootElement>
I don't know how to specify the OptionalElement as optional. There can be only one RootElement so I cannot add another one lacking the OptionalElement. How can I tell the parser, that OptionalElement is actually optional?
Upvotes: 1
Views: 367
Reputation: 233277
The XML Type Provider works by inferring the type from the sample. You can provide more than one sample by using the optional SampleIsList
argument:
open FSharp.Data
type RootElement = XmlProvider<"""
<samples>
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<OptionalElement> ... </OptionalElement>
<AnotherElement> ... </AnotherElement>
</RootElement>
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<AnotherElement> ... </AnotherElement>
</RootElement>
</samples>""", SampleIsList = true>
From this list of samples, the XML Type Provder infers that OptionalElement
is, well... optional, and types it as a string option
:
let x = RootElement.Parse """
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<OptionalElement> ... </OptionalElement>
<AnotherElement> ... </AnotherElement>
</RootElement>"""
let y = RootElement.Parse """
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<AnotherElement> ... </AnotherElement>
</RootElement>"""
Usage:
> y.OptionalElement.IsSome;;
val it : bool = false
> x.OptionalElement.IsSome;;
val it : bool = true
> x.OptionalElement |> Option.get;;
val it : string = " ... "
Upvotes: 1
Reputation: 80805
There is no way to explicitly specify "optional" within XML itself. The XML type provider infers this if it sees the element in some places, but not others, but that is only an educated guess.
For explicitly, strictly specifying which elements are optional, which can be multiple, etc., we have something called "XML Schema", also known as "XSD". Unfortunately, the XML type provider does not support XSD at the moment, although there is an open issue for it.
One hack I can offer you is this: make your root element nested under another, "super-root" element, and then make two of the "real root" ones, which will let the type provider infer the optional-ness. The type provider will then generate a "super-root" type for you, which you can promptly disregard, and only use the nested one, the real root.
Of course, since XML Type Provider, sadly, doesn't support parsing non-root elements, you will also have to "wrap" the XML text in the "super-root" element every time you parse it, which limits the solution to small documents only.
type Xml = XmlProvider<"""
<SuperRoot>
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<OptionalElement> ... </OptionalElement>
<AnotherElement> ... </AnotherElement>
</RootElement>
<RootElement>
<MandatoryElement> ... </MandatoryElement>
<AnotherElement> ... </AnotherElement>
</RootElement>
</SuperRoot>
""">
let parse xml = (Xml.Parse ("<SuperRoot>" + xml + "</SuperRoot>")).RootElements.[0]
Upvotes: 0