Парсинг XML-файла с F# linq к XML

Новичок F#

У меня есть 2 XML-файла в 2 папках c:\root\a\file.xml и c:\root\b\file.xml

У них есть идентичная структура:

<parent>
   <property name="firstName">Jane</property>
   <property name="lastName">...</property>
   <property name="dateOfBirth">...</property>>
</parent>

Я должен, выбрал файл который узел свойства с именем firstName имеет значение Jane.

В F# (возможно при помощи System.Xml.Linq) Я попробовал несколько решений, но ни один работающий до сих пор. Кто-либо готовый помочь?

13
задан CCovey 9 April 2015 в 21:31
поделиться

3 ответа

Было бы полезно, если бы вы могли показать какой-нибудь код, который вы пробовали, - затем кто-нибудь может объяснить, в чем проблема, чтобы вы могли узнать больше, чем когда кто-то просто размещает код, который работает. В любом случае вам нужно будет сослаться на некоторые сборки с помощью System.Xml.Linq и сначала открыть пространство имен. В интерактивном F # вы можете написать это так (в проекте F # просто используйте диалоговое окно Добавить ссылку ):

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

При использовании XLinq в F # вам понадобится простая служебная функция для преобразования строк в XName объект (который представляет имя элемента / атрибута). В C # есть неявное преобразование, но, к сожалению, это не работает в F #.

let xn s = XName.Get(s)

Затем вы можете загрузить свой XML-документ с помощью класса XDocument и использовать метод Element , чтобы получить единственный «родительский» элемент. Затем вы можете вызвать Elements , чтобы получить все вложенные элементы «свойства»:

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

Теперь вы можете искать элементы, чтобы найти один элемент с указанным значением атрибута.Например, используя Seq.tryFind (который также позволяет обрабатывать случай, когда элемент не найден):

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

Теперь значение nameOpt имеет тип option , чтобы вы могли сопоставить его с образцом, чтобы увидеть, был ли элемент найден (например, Some (el) ) или не был найден ( None ).

РЕДАКТИРОВАТЬ: Другой способ записать это - использовать выражения последовательности, а затем просто взять первый элемент (это не относится к случаю, когда элемент не найден):

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
37
ответ дан 1 December 2019 в 17:26
поделиться

Для этого не нужно использовать LINQ. Вот один из способов сделать это:

open System.Xml.XPath

let getName (filename:string) =
  let xpath = XPathDocument(filename).CreateNavigator()
  let node = xpath.SelectSingleNode(@"parent/property[@name='firstName']")
  node.Value

let files = [@"c:\root\a\file.xml"; @"c:\root\b\file.xml"]
let fileForJane = files |> List.find (fun file -> getName file = "Jane")
12
ответ дан 1 December 2019 в 17:26
поделиться

Также, вы можете смешать решение kvb с оператором (?):

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"
6
ответ дан 1 December 2019 в 17:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: