2010-06-09 72 views
2

基本上我想有一個單一的構造來處理序列化到JSON和格式化的XML。記錄很適合序列化到/從JSON。但是XmlSerializer需要一個無參數的構造器。我並不想通過爲這些結構構建類對象(僅適用於原理)。我希望可以有一些快捷方式讓一個無參數的構造函數到一個記錄上(也許有一個wioth語句或某個東西)。我無法做到這一點 - 社區中有沒有人有幸運?F#將構造函數添加到記錄中?

module JSONExample 
    open System 
    open System.IO 
    open System.Net 
    open System.Text 
    open System.Web 
    open System.Xml 
    open System.Security.Authentication 
    open System.Runtime.Serialization //add assemnbly reference System.Runtime.Serialization System.Xml 
    open System.Xml.Serialization 
    open System.Collections.Generic 

    [<DataContract>]    
    type ChemicalElementRecord = { 
     [<XmlAttribute("name")>] 
     [<field: DataMember(Name="name") >] 
     Name:string 

     [<XmlAttribute("name")>] 
     [<field: DataMember(Name="boiling_point") >] 
     BoilingPoint:string 

     [<XmlAttribute("atomic-mass")>] 
     [<field: DataMember(Name="atomic_mass") >] 
     AtomicMass:string 
    } 

    [<XmlRoot("freebase")>] 
    [<DataContract>] 
    type FreebaseResultRecord = { 
     [<XmlAttribute("code")>] 
     [<field: DataMember(Name="code") >] 
     Code:string 

     [<XmlArrayAttribute("results")>] 
     [<XmlArrayItem(typeof<ChemicalElementRecord>, ElementName = "chemical-element")>] 
     [<field: DataMember(Name="result") >] 
     Result: ChemicalElementRecord array 

     [<XmlElement("message")>] 
     [<field: DataMember(Name="message") >] 
     Message:string 
     } 


    let getJsonFromWeb() = 
     let query = "[{'type':'/chemistry/chemical_element','name':null,'boiling_point':null,'atomic_mass':null}]" 
     let query = query.Replace("'","\"") 
     let queryUrl = sprintf "http://api.freebase.com/api/service/mqlread?query=%s" "{\"query\":"+query+"}" 

     let request : HttpWebRequest = downcast WebRequest.Create(queryUrl) 
     request.Method <- "GET" 
     request.ContentType <- "application/x-www-form-urlencoded" 

     let response = request.GetResponse() 

     let result = 
      try 
       use reader = new StreamReader(response.GetResponseStream()) 
       reader.ReadToEnd(); 
      finally 
       response.Close() 

     let data = Encoding.Unicode.GetBytes(result); 
     let stream = new MemoryStream() 
     stream.Write(data, 0, data.Length); 
     stream.Position <- 0L 
     stream 



    let test = 
     // get some JSON from the web 
     let stream = getJsonFromWeb() 

     // convert the stream of JSON into an F# Record 
     let JsonSerializer = Json.DataContractJsonSerializer(typeof<FreebaseResultRecord>) 
     let result: FreebaseResultRecord = downcast JsonSerializer.ReadObject(stream) 

     // save the Records to disk as JSON 
     use fs = new FileStream(@"C:\temp\freebase.json", FileMode.Create) 
     JsonSerializer.WriteObject(fs,result) 
     fs.Close() 

     // save the Records to disk as System Controlled XML 
     let xmlSerializer = DataContractSerializer(typeof<FreebaseResultRecord>); 
     use fs = new FileStream(@"C:\temp\freebase.xml", FileMode.Create) 
     xmlSerializer.WriteObject(fs,result) 
     fs.Close() 

     use fs = new FileStream(@"C:\temp\freebase-pretty.xml", FileMode.Create) 
     let xmlSerializer = XmlSerializer(typeof<FreebaseResultRecord>) 
     xmlSerializer.Serialize(fs,result) 
     fs.Close() 

ignore(test) 

回答

1

看起來你無法記錄更改爲一類 - 或添加edfault構造它。

提供的示例(基於此文章:http://blogs.msdn.com/b/jomo_fisher/archive/2010/03/06/neat-sample-f-and-freebase.aspx)從api.freebase.com獲取json流;然後我們反序列化爲屬性類;接下來將其序列化爲Json到磁盤;然後將它作爲Xml序列化到磁盤(使用DataContract);最後,與輸出的最佳控制研究序列爲XML到磁盤(使用XmlSerializer的):

注:

DataContract(家庭)屬性 DataContractJsonSerializer和 JSON.DataContractJsonSerializer - 這些發生超過班級名稱和記憶變量。 DataContract 的東西很簡單 - 也適用於記錄類型。

XmlSerializer(系列)屬性 類和屬性 Getter/Setter。這要求類型 是具有默認 構造函數的對象,以及屬性Getters和 具有與它們中的每個相關聯的 屬性的設置器。如果一個屬性不 有eitehr一個getter或setter方法它 不會序列化 - 這是一個 驚喜(我想象中的默認 onstructor將確保 對象在 反序列化有defulat值和setter方法會 更新與任何序列化 - 但沒有這不是這種情況)。

另一個漂亮(嘆氣)件事 XmlSerialization是,類 不能被包含在一個模塊內。所以 我們移動種類多達命名空間...

namespace JSONExample 
    open System 
    open System.IO 
    open System.Net 
    open System.Text 
    open System.Web 
    open System.Xml 
    open System.Security.Authentication 
    open System.Runtime.Serialization //add assemnbly reference System.Runtime.Serialization System.Xml 
    open System.Xml.Serialization 
    open System.Collections.Generic 

    [<DataContract>]    
    type ChemicalElementRecord() = 
     [<field: DataMember(Name="name") >] 
     let mutable name: string = "" 

     [<field: DataMember(Name="boiling_point") >] 
     let mutable boilingPoint: string ="" 

     [<field: DataMember(Name="atomic_mass") >] 
     let mutable atomicMass: string = "" 

     [<XmlAttribute("name")>] 
     member this.Name with get() = name and set v = name <- v 

     [<XmlAttribute("boiling-point")>] 
     member this.BoilingPoint with get() = boilingPoint and set v = boilingPoint <- v 

     [<XmlAttribute("atomic-mass")>] 
     member this.AtomicMass with get() = atomicMass and set v = atomicMass <- v 

    [<XmlRoot("freebase")>] 
    [<DataContract>] 
    type FreebaseResultRecord() = 

     [<field: DataMember(Name="code") >] 
     let mutable code: string = "" 

     [<field: DataMember(Name="result") >] 
     let mutable result: ChemicalElementRecord array = Array.empty 

     [<field: DataMember(Name="message") >] 
     let mutable message: string = "" 

     [<XmlElement("message")>] 
     member this.Message with get() : string = message and set v = message <- v 

     [<XmlArrayAttribute("chemical-elements")>] 
     [<XmlArrayItem(typeof<ChemicalElementRecord>, ElementName = "chemical-element")>] 
     member this.Result with get() = result and set v = result <- v 

     [<XmlAttribute("code")>] 
     member this.Code with get() = code and set v = code <- v 

    module Test = 
     let getJsonFromWeb() = 
      let query = "[{'type':'/chemistry/chemical_element','name':null,'boiling_point':null,'atomic_mass':null}]" 
      let query = query.Replace("'","\"") 
      let queryUrl = sprintf "http://api.freebase.com/api/service/mqlread?query=%s" "{\"query\":"+query+"}" 

      let request : HttpWebRequest = downcast WebRequest.Create(queryUrl) 
      request.Method <- "GET" 
      request.ContentType <- "application/x-www-form-urlencoded" 

      let response = request.GetResponse() 

      let result = 
       try 
        use reader = new StreamReader(response.GetResponseStream()) 
        reader.ReadToEnd(); 
       finally 
        response.Close() 

      let data = Encoding.Unicode.GetBytes(result); 
      let stream = new MemoryStream() 
      stream.Write(data, 0, data.Length); 
      stream.Position <- 0L 
      stream 



     let test = 
      // get some JSON from the web 
      let stream = getJsonFromWeb() 

      // convert the stream of JSON into an F# Record 
      let JsonSerializer = Json.DataContractJsonSerializer(typeof<FreebaseResultRecord>) 
      let result: FreebaseResultRecord = downcast JsonSerializer.ReadObject(stream) 

      // save the Records to disk as JSON 
      use fs = new FileStream(@"C:\temp\freebase.json", FileMode.Create) 
      JsonSerializer.WriteObject(fs,result) 
      fs.Close() 

      // save the Records to disk as System Controlled XML 
      let xmlSerializer = DataContractSerializer(typeof<FreebaseResultRecord>); 
      use fs = new FileStream(@"C:\temp\freebase.xml", FileMode.Create) 
      xmlSerializer.WriteObject(fs,result) 
      fs.Close() 

      use fs = new FileStream(@"C:\temp\freebase-pretty.xml", FileMode.Create) 
      let xmlSerializer = XmlSerializer(typeof<FreebaseResultRecord>) 
      xmlSerializer.Serialize(fs,result) 
      fs.Close() 


     ignore(test) 
1

爲什麼不使用DataContractSerializer(用於Xml)而不是XmlSerializer?這是數據合同的主要優點之一(針對多個投影的相同編程模型)。

(有沒有辦法讓一個F#記錄一個參數的構造函數)。

+0

您可以控制DataContractSerializer的XML的輸出格式嗎?我最初嘗試過,並沒有太出色。正如你所看到的,我有三個磁盤分區,secnod分區使用這種格式。 – akaphenom 2010-06-09 17:04:35

+0

我想真正的問題是命名空間和i.Nil屬性的添加... – akaphenom 2010-06-09 17:08:40

+0

我明白了。快速的網頁搜索建議否;見例如http://stackoverflow.com/questions/1953984/is-there-a-way-to-make-datacontractserializer-output-cleaner-xml – Brian 2010-06-09 17:32:20

3

大段引用我希望有可能會有一些快捷方式獲取參數的構造函數到記錄

這是可能的在F#版本3.0中通過使用CLIMutable屬性。將它添加到無參數構造函數的記錄類型和讀/寫屬性(而不是隻讀屬性)。

相關問題