2010-10-27 57 views
11

我知道如何使用可變對象在F#中進行序列化,但是有沒有辦法使用XmlSerializer或DataContractSerializer使用記錄類型來序列化/反序列化?貌似有一種方法可以使用KnownType屬性識別聯合做到這一點,但是我正在尋找一種方式來使用非可變記錄沒有默認構造函數...記錄類型的F#序列化

+0

我結束了剛剛使用XML解析,這在我的情況,以及我試圖沒有工作產生乾淨的XML,即使托馬斯的建議使用System.Xml.Serialization的屬性,我的懷疑是它是不會工作,但我決定嘗試反正他們沒有,我相信因爲datacontract的命名空間忽略了這些。我的要求是在這個練習中使用非可變記錄,但是如果你的目標只是xml序列化,那麼它就和以任何其他.net語言使用它沒什麼兩樣,只需創建類,裝飾它們並使用XmlSerializer,它就可以工作。 – Alex 2010-11-29 16:27:29

回答

9

樣品code for reading data from Freebase由喬莫·費希爾使用DataContractJsonSerializer到將數據加載到不可變的F#記錄中。記錄的聲明,他使用這個樣子的:

[<DataContract>] 
type Result<'TResult> = { // ' 
    [<field: DataMember(Name="code") >] 
    Code:string 
    [<field: DataMember(Name="result") >] 
    Result:'TResult // ' 
    [<field: DataMember(Name="message") >] 
    Message:string } 

這裏的關鍵點是,在DataMember屬性附加到這實際上是用來存儲數據,而不是隻讀屬性的基礎字段F#編譯器生成(使用屬性上的field:修飾符)。

我不是100%肯定這是否會與其他類型的序列化(可能不是)工作,但它可能是一個有用的指針開始...

編輯我不知道如果我失去了一些東西,但以下基本示例工作正常,我:

module Demo 

#r "System.Runtime.Serialization.dll" 

open System.IO 
open System.Text 
open System.Xml 
open System.Runtime.Serialization 

type Test = 
    { Result : string[] 
    Title : string } 

do 
    let sb = new StringBuilder() 
    let value = { Result = [| "Hello"; "World" |]; Title = "Hacking" } 
    let xmlSerializer = DataContractSerializer(typeof<Test>); 
    xmlSerializer.WriteObject(new XmlTextWriter(new StringWriter(sb)), value) 
    let sr = sb.ToString() 
    printfn "%A" sr 

    let xmlSerializer = DataContractSerializer(typeof<Test>); 
    let reader = new XmlTextReader(new StringReader(sr)) 
    let obj = xmlSerializer.ReadObject(reader) :?> Test 
    printfn "Reading: %A" obj 

EDIT 2如果你想生成XML更清潔,那麼你可以添加的屬性是這樣的:

[<XmlRoot("test")>] 
type Test = 
    { [<XmlArrayAttribute("results")>] 
    [<XmlArrayItem(typeof<string>, ElementName = "string")>] 
    Result : string[] 
    [<XmlArrayAttribute("title")>] 
    Title : string } 
+0

這是一個開始,但生成的xml不是「乾淨的」,我的意思是標籤就像「FSI_0132」。測試「,而不是測試和Title_x0040_而不是標題。我也看起來像不能使用[]屬性的類型設置xml標記。換句話說,xml看起來中間,而不是我真的可以使用.btw,Tomas,我開始閱讀你的真實世界功能編程書,它看起來非常好迄今。 – Alex 2010-10-27 17:02:19

+0

命名空間「FSI_0132」由F#Interactive生成 - 在編譯後的代碼中,它將替換爲實際的命名空間。不知道的屬性名稱,但 – 2010-10-27 17:12:53

+0

@Joel:對,我明白,但我的目標是有乾淨的XML沒有任何名稱空間的信息,就像您如果你試圖在.NET – Alex 2010-10-27 17:24:32

1

您可以使用這一系列的註解上的類的屬性設置格式的XML:

[XmlRoot("root")] 
[XmlElement("some-element")] 
[XmlAttribute("some-attribute")] 
[XmlArrayAttribute("collections")] 
[XmlArrayItem(typeof(SomeClass), ElementName = "item")] 

我使用的屬性在我的C#類,但在F#反序列化(C#類INA引用LIB)。

在F#

use file = new FileStream(filePath, FileMode.Open) 
let serializer= XmlSerializer(typeof<SomeClass>) 
let docs = serializer.Deserialize file :?> SomeClass 
+1

這很酷,但要求是使用非可變類型,所以這方法將無法正常工作,因爲該類將有可變字段 – Alex 2010-10-27 20:21:33

9

它不使用的XmlSerializer或DataContractSerializer的,但Json.NET 6.0 includes nice F# support.

它看起來像這樣:

type TestTarget = 
    { a: string 
     b: int } 

[<TestFixture>] 
type JsonTests() = 
    [<Test>] 
    member x.``can serialize``() = 
     let objectUnderTest = { TestTarget.a = "isa"; b = 9 } 
     let jsonResult: string = Newtonsoft.Json.JsonConvert.SerializeObject(objectUnderTest) 
     printfn "json is:\n%s" jsonResult 
     let xmlResult = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonResult, "root") 
     printfn "xml is:\n%s" (xmlResult.OuterXml) 

     let jsonRoundtrip = Newtonsoft.Json.JsonConvert.DeserializeObject<TestTarget>(jsonResult) 
     printfn "json roundtrip: %A" jsonRoundtrip 

     let xmlAsJson = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlResult, Newtonsoft.Json.Formatting.Indented, true) 
     printfn "object -> json -> xml -> json:\n%A" xmlAsJson 
     let xmlRoundtrip = Newtonsoft.Json.JsonConvert.DeserializeObject<TestTarget>(xmlAsJson) 
     printfn "xml roundtrip:\n%A" xmlRoundtrip 

     Assert.That(true, Is.False) 
     () 

json is: 
{"a":"isa","b":9} 
xml is: 
<root><a>isa</a><b>9</b></root> 
json roundtrip: {a = "isa"; 
b = 9;} 
object -> json -> xml -> json: 
"{ 
    "a": "isa", 
    "b": "9" 
}" 
xml roundtrip: 
{a = "isa"; 
b = 9;} 
+0

真棒,用於顯示使用記錄類型的方式,而不需要'[]'attr(只需升級newto nsoft) – Maslow 2015-02-01 16:46:41

+0

我發現這並不尊重成員名稱的大小寫敏感性(它們總是轉換爲小寫)。 – 2015-10-05 17:17:57