Parsing XML file with F# linq to XML Parsing XML file with F# linq to XML xml xml

Parsing XML file with F# linq to XML


It would be useful if you could show some code that you tried - someone can then explain what is the problem, so you can learn more than when someone just posts code that works. Anyway, you'll need to reference some assemblies with the System.Xml.Linq and open the namespace first. In F# interactive, you can write it like this (in F# project, just use Add Reference dialog):

#r "System.Core.dll"#r "System.Xml.Linq.dll"open System.Xml.Linq

When using XLinq in F#, you need a simple utility function for converting strings to XName object (which represents an element/attribute name). There is an implicit conversion in C#, but this sadly doesn't work in F#.

let xn s = XName.Get(s)

Then you can load your XML document using the XDocument class and use Element method to get a single "parent" element. Then you can call Elements to get all nested "property" elements:

let xd = XDocument.Load("file.xml")let props = xd.Element(xn "parent").Elements(xn "property")

Now you can search the elements to find the one element with the specified attribute value. For example using Seq.tryFind (which also allows you to handle the case when the element is not found):

let nameOpt = props |> Seq.tryFind (fun xe ->   xe.Attribute(xn "name").Value = "firstName")

Now, the value nameOpt is of type option<XElement> so you can pattern match on it to see if the element was found (e.g. Some(el)) or if it wasn't found (None).

EDIT: Another way to write this is to use sequence expressions and then just take the first element (this doesn't handle the case when element is not found):

let nameEl =   seq { for el in xd.Element(xn "parent").Elements(xn "property") do          if xe.Attribute(xn "name").Value = "firstName" then yield xe }  |> Seq.head


You don't need to use LINQ for this. Here's one way to do it:

open System.Xml.XPathlet getName (filename:string) =  let xpath = XPathDocument(filename).CreateNavigator()  let node = xpath.SelectSingleNode(@"parent/property[@name='firstName']")  node.Valuelet files = [@"c:\root\a\file.xml"; @"c:\root\b\file.xml"]let fileForJane = files |> List.find (fun file -> getName file = "Jane")


Also, you can mix kvb's solution with (?) operator:

let (?) (fname: string) (nodeName: string) : string =  let xpath = XPathDocument(fname).CreateNavigator()  let node = xpath.SelectSingleNode(@"parent/property[@name='"^nodeName^"']")  node.Value;;val ( ? ) : string -> string -> string> "i:/a.xml"?firstName;;val it : string = "Jane"