I want to make use of data like this
[<Literal>]
let AJsonString =
"""{
"Meta Data": {
"1. Information": "Daily Time Series with Splits and Dividend Events",
"2. Symbol": "MSFT",
"3. Last Refreshed": "2019-07-17",
"4. Output Size": "Compact",
"5. Time Zone": "US/Eastern"
},
"Time Series (Daily)": {
"2019-07-17": {
"1. open": "137.7000",
"2. high": "137.9300",
"3. low": "136.2200",
"4. close": "136.2700",
"5. adjusted close": "136.2700",
"6. volume": "20072925",
"7. dividend amount": "0.0000",
"8. split coefficient": "1.0000"
},
"2019-07-16": {
"1. open": "138.9600",
"2. high": "139.0500",
"3. low": "136.5200",
"4. close": "137.0800",
"5. adjusted close": "137.0800",
"6. volume": "22726128",
"7. dividend amount": "0.0000",
"8. split coefficient": "1.0000"
}
}
}"""
type TimeSeriesPrices = JsonProvider<AJsonString>
let test = TimeSeriesPrices.GetSample().TimeSeriesDaily.``20190717``
https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=MSFT&apikey=demo
I would like to use JsonProvider, but it parses each date as a named item (to be fair, that is how it is represented in the json).
As you can see, 29190717
is a named element. But in general, this date might not exist.
Is there a simple way to get JsonProvider to parse this as an array of items, or do I have to manually parse in this case?
There is no way to tell the JsonProvider
that it should treat a particular record as an array - records will always be mapped to objects with members. People seem to sometimes use records this way, so an extension to the type provider along those lines might be nice addition (despite my feeling that it's wrong :-))
That said, you can take some advantage of the provided types - to get the properties of the record, you'll need to get Properties
of JsonValue
as an array, but you can then wrap the records with actual data back in the provided type:
type TimeSeriesPrices = JsonProvider<AJsonString, InferTypesFromValues=true>
let data = TimeSeriesPrices.GetSample()
for k, v in data.TimeSeriesDaily.JsonValue.Properties() do
let v = TimeSeriesPrices.``20190717``(v)
printfn "%s %A" k v.``1Open``
The call to TimeSeriesPrices.''20190717''
in the for
loop wraps the value in the provided type for the nested record, so you can then access 1Open
(and all the other fields) as a regular member. I also added InferTypesFromValues=true
which makes the type provider infer 1Open
as decimal
(rather than string).
The type name TimeSeriesPrices.''20190717''
is quite ugly - if you replace the first key (i.e. the date 2019-07-17
) in your sample file with a nicer name like Data
, the type provider will give you that, which is probably a good idea!