2010-06-09 6 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 스트림을 가져옵니다. 우리는 속성 클래스로 deserialize; 다음으로 Json으로 디스크에 직렬화하십시오; 그런 다음 Xml을 디스크로 직렬화합니다 (DataContract 사용).

참고 : 마지막으로, 출력의 최적의 설정 제어와 디스크 (XmlSerializer를 사용) XML로 직렬화

DataContract (가족) DataContractJsonSerializer 및 JSON.DataContractJsonSerializer 속성 - 이 발생 클래스 이름과 구성원 변수. DataContract 물건은 곧장 앞으로 - 그리고 뿐만 아니라 레코드 유형에서 작동합니다.

클래스의 XmlSerializer (패밀리) 특성 및 속성 게터/설정자. 이 유형은 유형이 기본값 생성자가 있고 Getters 및 속성이 각각 과 연결된 속성이있는 객체입니다. 깜짝이었다 (나는 onstructor가 객체가 직렬화에 defulat 값을 가지고 있는지 확인 할 기본을 상상하고 세터 업데이 트를 것 - 속성이되지 않는 경우 는 eitehr 게터하거나 직렬화되지 않습니다 세터가 무엇이든 직렬화되었으므로 - 하지만 그렇지 않습니다.

또 다른 멋진 (한숨) 일에 대한 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

XmlSerializer 대신 Xml 용 DataContractSerializer를 사용하지 않는 이유는 무엇입니까? 이는 데이터 계약의 주요 이점 중 하나입니다 (여러 프로젝션에 대해 동일한 프로그래밍 모델).

은 (AN F 번호 레코드에 대한 매개 변수가없는 생성자를 만들 수있는 방법이 없습니다.) 당신이 클래스에 레코드를 변경할 수 없습니다처럼

+0

DataContractSerializer에 대한 XML의 출력 형식을 제어 할 수 있습니까? 나는 원래 시도해 보니 너무 기분이 좋지 않았다. 당신이 볼 수 있듯이 나는 디스크에 3 개의 serializaiton을 가지고 있고 secnod는 그 포맷을 사용한다. – akaphenom

+0

실제 문제는 네임 스페이스와 i.Nil 속성을 추가 한 것입니다 ... – akaphenom

+0

알겠습니다. 빠른 웹 검색은 아니오를 제안합니다. 예를 들어 http://stackoverflow.com/questions/1953984/is-there-a-way-to-make-datacontractserializer-output-cleaner-xml – Brian

3

인용문 나는 기록에 매개 변수없는 생성자를 얻기위한 몇 가지 바로 가기를 수있을 기대했다하는

이 가능하다 ... 네임 스페이스까지 종류를 이동 f # 버전 3.0에서는 CLIMutable 속성을 사용합니다.매개 변수없는 생성자 및 읽기 전용 속성 (읽기 전용 속성 대신)에 대한 레코드 유형에이 값을 추가하십시오.

관련 문제