Десериализация Xml с помощью F # - PullRequest
0 голосов
/ 01 апреля 2011

Я получаю следующий XML-файл от веб-службы, который хочу преобразовать в объекты .net:

let xmlString = "<?xml version=\"1.0\"?>
<logInResponse>
  <result>OK</result>
  <xmlLogIn>
    <session>11C0ED6F8F7288855FC73C99979A9732.TOGKE6VP9aE8abcdLXaVXg</session>
    <user>WallStreetScumbag1</user>
    <authorizations>
      <insiderTrading>true</insiderTrading>
    </authorizations>
  </xmlLogIn>
</logInResponse>"

Это то, что я имею до сих пор:

type Result(value:XmlNode) = 
    member this.Value = value.InnerText

let (|Node|Result|) (node : #System.Xml.XmlNode) =
    if node.Name = "result" then
        Result (new Result(node))
    else
        Node (seq {for x in node.ChildNodes -> x})

let extract node =
    let rec extract node =
        match node with 
        | Result(p) ->
            Seq.singleton p
        | Node(nodes) ->
            Seq.collect (fun (n) -> extract n) nodes
    extract node

let xmlDoc = new XmlDocument()
xmlDoc.LoadXml(xmlString)

//type LogIn() =
    //This is where I would create a .net object that mirrors the xml.

Как вы можете видеть, некоторые элементы повторяются в разных элементах, и иногда элементы не включают в себя все элементы, которые могут отображаться, как вы можете видеть в моем примере xml. Этот же веб-сервис также будет использовать многие из этих элементов в других типах ответов. Можно ли использовать активные шаблоны для создания общего способа десериализации xml, который я получаю обратно в объекты? Похоже, что этот веб-сервис никогда не использует атрибуты для отправки информации, все это кажется элементами внутри элементов, которые могут облегчить эту проблему. Если я поступаю неправильно, пожалуйста, не стесняйтесь предлагать что-то лучшее.

Заранее спасибо,

Bob

1 Ответ

0 голосов
/ 01 апреля 2011

Ваш подход к использованию активных шаблонов для сопоставления различных типов узлов мне подходит. Я бы, вероятно, использовал частичные шаблоны (которые могут возвращать Some, когда они совпадают, или None) вместо полных шаблонов (которые всегда возвращают один из случаев). Это позволяет вам написать несколько шаблонов для разных типов узлов, с которыми вы работаете.

let (|Result|_|) (node:#System.Xml.XmlNode) =
  if node.Name = "result" then
    Some(new Result(node))
  else
    None

В сопоставлении с образцом вы можете включить столько частичных рисунков, сколько захотите, и охватить все оставшиеся случаи, используя _ (шаблон с подстановочными знаками):

match node with 
| Result(p) ->
    Seq.singleton p
| nd ->
    Seq.collect (fun (n) -> extract n) nd.ChildNodes

Кроме этого, я не уверен, что структура в вашем примере выглядит вполне правильной, поэтому вам не нужно обрабатывать случаи, как в HTML (где <a> может быть вложено в другие элементы). Кажется, вы можете просто представить основную часть XML в виде списка учетных записей (и проанализировать все свойства учетных записей, используя активные шаблоны).

...