F# newbie
I have 2 XML files in 2 folders c:\root\a\file.xml
and c:\root\b\file.xml
They have identical structure:
<parent>
<property name="firstName">Jane</property>
<property name="lastName">...</property>
<property name="dateOfBirth">...</property>>
</parent>
I need to chose the file which property node with name firstName
has the value Jane.
In F# (possibly by using System.Xml.Linq
)
I have tried several solutions but none working so far. Anyone willing to help?
Just about every browser can open an XML file. In Chrome, just open a new tab and drag the XML file over. Alternatively, right click on the XML file and hover over "Open with" then click "Chrome". When you do, the file will open in a new tab.
To include special characters inside XML files you must use the numeric character reference instead of that character. The numeric character reference must be UTF-8 because the supported encoding for XML files is defined in the prolog as encoding="UTF-8" and should not be changed.
There are two ways to parse the file using 'ElementTree' module. The first is by using the parse() function and the second is fromstring() function. The parse () function parses XML document which is supplied as a file whereas, fromstring parses XML when supplied as a string i.e within triple quotes.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With