I am trying to parse a directory of XML files and then select the value of particular attribute if a given node is present. Am not able to understand the reason for the compilation error that the following F# is causing.
open System
open System.IO
open System.Xml
open System.Xml.XPath
open System.Xml.Linq
let configRootDirectory = @"C:\dir"
let relativeProductDir = @"relDir"
let ExtractConfiguredCalculator (productConfigFile:string) =
let xmlNavigator = XPathDocument(productConfigFile).CreateNavigator()
let node = xmlNavigator.SelectSingleNode(@"Product/SupportedRisk/Risk[@type='PV']")
node.GetAttribute("methodology", "")
let configFile = Directory.GetFiles(Path.Combine(configRootDirectory, relativeProductDir), @"*.xml")
|> Seq.cast<string>
|> Seq.iter(fun configFileName -> ExtractConfiguredCalculator(configFileName))
|> Seq.filter(fun configuredCalculatorNode -> configuredCalculatorNode != null)
|> Seq.iter(fun calculator -> Console.WriteLine(calculator))
The above snippet is from the code that I am experimenting with in LinqPad. The error message seen is as below.
This expression was expected to have type unit but here has type string
Update Trying to get more f#-ish. Please suggest if something can be improved.
let configFile =
Directory.GetFiles(Path.Combine(configRootDirectory, relativeProductDir), @"*.xml")
|> Seq.map(fun configFileName ->
let xmlNavigator = XPathDocument(configFileName).CreateNavigator()
let node = xmlNavigator.SelectSingleNode(@"Product/SupportedRisk/Risk[@type='PV']")
match node with
| null -> "PV not configured"
| _ ->
let attributeValue = node.GetAttribute("methodology", "")
match attributeValue with
| null -> "Calculator not configured"
| _ -> attributeValue)
|> Seq.iter (printfn "%s")
You have to change the first Seq.iter
to Seq.map
to return a sequence which is required by the subsequent Seq.filter
.
I have several comments though:
Seq.cast
is redundant since Directory.GetFiles
returns string []
.Seq.map
and Seq.filter
together, you could always replace them by Seq.choose
.printfn
is a more F#ish way of printing than Console.WriteLine
.Here is an improved version:
let configFile =
Directory.GetFiles(Path.Combine(configRootDirectory, relativeProductDir), @"*.xml")
|> Seq.choose (fun configFileName ->
let config = ExtractConfiguredCalculator(configFileName)
if config <> null then Some config else None)
|> Seq.iter (printfn "%s")