【问题标题】:Deserializing twitter stream json string F#, how to define 'null' as a proper value?反序列化twitter流json字符串F#,如何将'null'定义为正确的值?
【发布时间】:2011-04-17 05:18:56
【问题描述】:

如果有人想要记录类型,我会留下以下内容,但我的问题可以如下提出。 假设需要将一个可以为空的记录类型写入文件,考虑到以下产生的最佳方法是什么:“'Basic' 类型没有'null' 作为正确值”:

type Basic = {Toto:string}

let basicToString b = function
    |null -> "null"
    |record->record.Toto

非常感谢


我有以下代码来反序列化 Twitter 流中的推文:

open System.Runtime.Serialization
open System.Runtime.Serialization.Json
open System
open System.Text
open System.IO  


  let  makeString numFields = 
    if numFields>1 then 
                seq[for i in 1..(numFields-1)->","]
                |> Seq.fold(fun elem res-> elem+res) ""
    else
        ""



[<DataContract>]
type boundingbox = {
    [<field: DataMember(Name = "type")>]
    t:string
    [<field: DataMember(Name = "coordinates")>]
    coordinates:float array array array
    }
    with 
        member this.ToCsv() = let temp =  string this
                              if temp ="" then 
                                  makeString 2
                              else
                                  this.t+","+"coordinates"




[<DataContract>]
type attributes = {
 [<field: DataMember(Name = "street_adress")>]
 street_adress:string
 }
    with 
        member this.ToCsv() = let temp =  string this
                              if temp ="" then 
                                  makeString 1
                              else
                                  this.street_adress



[<DataContract>]
type place = {
    [<field: DataMember(Name = "country")>]
    country:string
    [<field: DataMember(Name = "url")>]
    url:string
    [<field: DataMember(Name = "attributes")>]
    attributes:attributes 
    [<field: DataMember(Name = "country_code")>]
    country_code:string
    [<field: DataMember(Name = "full_name")>]
    full_name:string
    [<field: DataMember(Name = "name")>]
    name:string
    [<field: DataMember(Name = "id")>]
    id:string
    [<field: DataMember(Name = "bounding_box")>]
    bounding_box:boundingbox
    [<field: DataMember(Name = "pldace_type")>]
    place_type:string
    }
    with 
        member this.toCsv() = let temp =  string this
                              if temp ="" then 
                                  makeString 10
                              else
                                  this.country+","+this.url+","+this.attributes.ToCsv()+","+this.country_code+","+this.full_name+","+this.name+","+this.bounding_box.ToCsv()+","+this.place_type



[<DataContract>]
type geo = {
    [<field: DataMember(Name = "type")>]
    t:string
    [<field: DataMember(Name = "coordinates")>]
    coordinates:float array
    }

[<DataContract>]
type url = {
    [<field: DataMember(Name = "url")>]
    url:string
    [<field: DataMember(Name = "indices")>]
    indices:int array
    }

[<DataContract>]
type hashtag = {
    [<field: DataMember(Name = "text")>]
    text:string
    [<field: DataMember(Name = "indices")>]
    indices:int array
    }


[<DataContract>]
type user_mention = {
    [<field: DataMember(Name = "indices")>]
    indices:int array
    [<field: DataMember(Name = "screen_name")>]
    screen_name:string
    [<field: DataMember(Name = "name")>]
    name:string
    [<field: DataMember(Name = "id")>]
    id:string
    }

[<DataContract>]
type entities = {
    [<field: DataMember(Name = "urls")>]
    urls:url array
    [<field: DataMember(Name = "hashtags")>]
    hashtags:hashtag array
    [<field: DataMember(Name = "user_mentions")>]
    user_mentions:user_mention array
    }

[<DataContract>]
type user = {
    [<field: DataMember(Name = "time_zone")>]
     time_zone:string
    [<field: DataMember(Name = "profile_sidebar_border_color")>]
     profile_sidebar_border_color:string
    [<field: DataMember(Name = "screen_name")>]
    screen_name:string
    [<field: DataMember(Name = "notifications")>]
     notifications:string
    [<field: DataMember(Name = "listed_count")>]
     listed_count:string
    [<field: DataMember(Name = "profile_background_image_url")>]
     profile_background_image_url:string
    [<field: DataMember(Name = "location")>]
    location:string
    [<field: DataMember(Name = "statuses_count")>]
     statuses_count:string
    [<field: DataMember(Name = "profile_background_color")>]
    profile_background_color:string
    [<field: DataMember(Name = "description")>]
     description:string
    [<field: DataMember(Name = "show_all_inline_media")>]
     show_all_inline_media:string
    [<field: DataMember(Name = "profile_background_tile")>]
     profile_background_tile:string
    [<field: DataMember(Name = "contributors_enabled")>]
     contributors_enabled:string
    [<field: DataMember(Name = "geo_enabled")>]
     geo_enabled:string
    [<field: DataMember(Name = "created_at")>]
     created_at:string
    [<field: DataMember(Name = "profile_text_color")>]
     profile_text_color:string
    [<field: DataMember(Name = "followers_count")>]
    followers_count:string
    [<field: DataMember(Name = "profile_use_background_image")>]
    profile_use_background_image:string
    [<field: DataMember(Name = "url")>]
     url:string
    [<field: DataMember(Name = "friends_count")>]
     friends_count:string
    [<field: DataMember(Name = "profile_link_color")>]
    profile_link_color:string
    [<field: DataMember(Name = "protected")>]
     Protected:string
    [<field: DataMember(Name = "lang")>]
     lang:string
    [<field: DataMember(Name = "verified")>]
     verified:string
    [<field: DataMember(Name = "name")>]
     name:string
    [<field: DataMember(Name = "follow_request_sent")>]
     follow_request_sent:string
    [<field: DataMember(Name = "following")>]
     following:string
    [<field: DataMember(Name = "favourites_count")>]
     favourites_count:string
    [<field: DataMember(Name = "profile_sidebar_fill_color")>]
     profile_sidebar_fill_color:string
    [<field: DataMember(Name = "profile_image_url")>]
    profile_image_url:string
    [<field: DataMember(Name = "id")>]
    id:string
    [<field: DataMember(Name = "utc_offset")>]
     utc_offset:string
}




[<DataContract>]
type tweet = {
    [<field: DataMember(Name = "place")>]
     place:place
    [<field: DataMember(Name = "geo")>]
     geo:geo
    [<field: DataMember(Name = "text")>]
    text:string
    [<field: DataMember(Name = "coordinates")>]
    coordinates:geo
    [<field: DataMember(Name = "retweet_count")>]
     retweet_count:string
    [<field: DataMember(Name = "favorited")>]
     favorited:string
    [<field: DataMember(Name = "source")>]
    source:string
    [<field: DataMember(Name = "contributors")>]
     contributors:int array
    [<field: DataMember(Name = "created_at")>]
    created_at:string
    [<field: DataMember(Name = "in_reply_to_status_id")>]
    in_reply_to_status_id:string
    [<field: DataMember(Name = "in_reply_to_screen_name")>]
    in_reply_to_screen_name:string
    [<field: DataMember(Name = "user")>]
     user:user
    [<field: DataMember(Name = "retweeted")>]
    retweeted:string
    [<field: DataMember(Name = "in_reply_to_user_id")>]
    in_reply_to_user_id:string
    [<field: DataMember(Name = "truncated")>]
     truncated:string
    [<field: DataMember(Name = "id")>]
    tweet_id:string
    [<field: DataMember(Name = "entities")>]
    entities:entities
    }



[<DataContract>]
type fullTweet = {
    [<field: DataMember(Name = "place")>]
     place:place
    [<field: DataMember(Name = "geo")>]
     geo:geo
    [<field: DataMember(Name = "text")>]
    text:string
    [<field: DataMember(Name = "coordinates")>]
    coordinates:geo
    [<field: DataMember(Name = "retweet_count")>]
     retweet_count:string
    [<field: DataMember(Name = "favorited")>]
     favorited:string
    [<field: DataMember(Name = "source")>]
    source:string
    [<field: DataMember(Name = "contributors")>]
     contributors:int array
    [<field: DataMember(Name = "created_at")>]
    created_at:string
    [<field: DataMember(Name = "in_reply_to_status_id")>]
    in_reply_to_status_id:string
    [<field: DataMember(Name="retweeted_status")>]
    retweeted_status:tweet
    [<field: DataMember(Name = "in_reply_to_screen_name")>]
    in_reply_to_screen_name:string
    [<field: DataMember(Name = "user")>]
     user:user
    [<field: DataMember(Name = "retweeted")>]
    retweeted:string
    [<field: DataMember(Name = "in_reply_to_user_id")>]
    in_reply_to_user_id:string
    [<field: DataMember(Name = "truncated")>]
     truncated:string
    [<field: DataMember(Name = "id")>]
    tweet_id:string
    [<field: DataMember(Name = "entities")>]
    entities:entities
    }



let decodeFullTweet (s:string)  = 
    let json = new DataContractJsonSerializer(typeof<fullTweet>)
    let byteArray = Encoding.UTF8.GetBytes(s)
    let stream = new MemoryStream(byteArray)
    json.ReadObject(stream) :?>fullTweet

let decodeUser (s:string)  = 
    let json = new DataContractJsonSerializer(typeof<user>)
    let byteArray = Encoding.UTF8.GetBytes(s)
    let stream = new MemoryStream(byteArray)
    json.ReadObject(stream) :?>user

我需要完成的下一步是将每个 fullTweet 记录写入 csv 文件,问题是有时记录类型的某些字段为空。比如解码json字符串时(下面只是一小部分字符串):

rel=\\"nofollow\\">TweetDeck\",\"favorited\":false,\"in_reply_to_status_id\":null,\"entities\":{\"hashtags\":[{\" text\":\"frac1\",\"indices\":[117,123]}],\"user_mentions\":[],\"urls\":[]},\"place\":null,\ "坐标\":null,\"geo\":null,\"in_reply_to_user_id\":null,\"

“place”和“in_reply_to_user_id”字段将为空。

我该如何处理,以便当字段为空(例如地点)时,csv 行读取“null”(对于记录类型地点的每个字段)?或者如果你有更好的方法来处理这个?

非常感谢!!!

(希望有些人会喜欢所有的记录类型:))

【问题讨论】:

  • 您是否已经有一些代码或想法如何生成 CSV 文件?否则,这个问题很难回答。如何处理空值取决于 CSV 文件的创建方式。
  • @wmeyer 感谢您查看此内容。我的问题不是很清楚,抱歉。我用一个“有效”的解决方案编辑了我的帖子,但它看起来有点难看。
  • 对您的问题没有答案,但发现您在 makeString 函数中对折叠的使用非常巧妙。但是,如果你想把它留给 F# 库,你可以使用 'let makeString numFields = String.init numFields (fun _ -> ",")' 代替。
  • @Alexander Rautenberg 感谢您的提示,使用 String.init 是一个更好的解决方案

标签: json api f# twitter


【解决方案1】:

如果我明白你在问什么,你只需要一个函数,它会接受一个字符串,如果它不为空则返回该字符串,如果它为空则返回“null”:

let fieldToString = function
    | null -> "null"
    | field -> field

【讨论】:

  • Swenson 感谢您的帮助,打印记录的字段,这将起作用(如果整体记录不为空)。真正的问题是,如果您尝试在完整记录上进行操作。我已经编辑了我原来的问题。
  • 你可以考虑[&lt;AllowNullLiteral&gt;]msdn.microsoft.com/en-us/library/ee353608.aspx
  • @Brian 谢谢。你知道反序列化时是否有使用选项类型。在fullTweet类型中,每个字段可以存在或不存在(None/Some),然后每个子字段可以存在或不存在(None/Some)等等。这样一个选项类型看起来很自然
  • F# 记录类型不允许空值,即使具有 AllowNullLiteral 属性:stackoverflow.com/questions/1856345
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-30
  • 1970-01-01
  • 2023-03-28
相关资源
最近更新 更多