4

基本的に、JSON とフォーマットされた xml の両方へのシリアル化を処理する単一の構造が必要です。Records は、json との間のシリアル化にうまく機能しました。ただし、XmlSerializer にはパラメーターなしのコンストラクターが必要です。これらのコンストラクトのクラス オブジェクトを作成する作業を実際に実行する必要はありません (原則のみ)。パラメーターなしのコンストラクターをレコードに取得するためのショートカットがあることを望んでいました (おそらく wioth ステートメントまたは何かを使用して)。私はそれを振る舞わせることができません - コミュニティの誰かが運が良かったのですか?

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)
4

3 に答える 3

8

パラメーターなしのコンストラクターをレコードに取得するためのショートカットがあることを望んでいました

これは、CLIMutable属性を使用して F# バージョン 3.0 で可能です。パラメーターなしのコンストラクターと読み取り/書き込みプロパティ (読み取り専用プロパティではなく) のレコード型にこれを追加します。

于 2012-10-29T18:06:28.593 に答える
1

XmlSerializer ではなく DataContractSerializer (Xml 用) を使用しないのはなぜですか? これは、データ コントラクトの主な利点の 1 つです (複数のプロジェクションに対して同じプログラミング モデルを使用できます)。

(F# レコードのパラメーターなしのコンストラクターを作成する方法はありません。)

于 2010-06-09T16:49:54.833 に答える
1

レコードをクラスに変更したり、edfault コンストラクターを追加したりできないようです。

提供されている例 (この記事に基づいています: http://blogs.msdn.com/b/jomo_fisher/archive/2010/03/06/neat-sample-f-and-freebase.aspx ) は、API から json のストリームを取得します.freebase.com; 次に、属性付きクラスに逆シリアル化します。次に、Json としてディスクにシリアル化します。次に、Xml としてディスクにシリアル化します (DataContract を使用)。最後に、出力を最適に制御して、Xml としてディスクにシリアル化します (XmlSerializer を使用)。

ノート:

DataContractJsonSerializer および JSON.DataContractJsonSerializer の DataContract (ファミリー) 属性 - これらは、クラス名およびメンバー変数に対して発生します。DataContract は簡単で、レコード タイプでも機能します。

クラスおよびプロパティ ゲッター/セッターに対する XmlSerializer (ファミリ) 属性。これには、タイプがデフォルトのコンストラクターを持つオブジェクトであり、それぞれに関連付けられた属性を持つプロパティ Getters および Setters が必要です。プロパティにゲッターまたはセッターのいずれかがない場合、シリアル化されません-これは驚きでした(デフォルトのコンストラクターは、逆シリアル化時にオブジェクトがデフォルト値を持ち、セッターがシリアル化されたもので更新されることを保証すると想像しました-しかし、そうではありませんこれは当てはまりません)。

XmlSerialization に関するもう 1 つの気の利いた (ため息) ことは、クラスをモジュール内に含めることができないことです。そのため、型を名前空間に移動します...

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)
于 2010-06-09T21:45:24.443 に答える