首页 > 解决方案 > 在不知道完整结构的情况下反序列化 JSON

问题描述

我正在重做一个非常基本的框架的后端,该框架连接到一个完全可定制的前端。它最初是在 PHP 中,但重构一直在 F# 中缓慢进行。虽然看起来 PHP 可能是更适合的语言。但是人们一直告诉我你可以在 F# 中做任何事情,我喜欢它的语法并且需要学习,而这个看似简单的项目让我在谈到 JSON 时很难过。这是我昨天的问题的进一步充实版本,但它比我想象的要复杂得多。

开始。

前端基本上是 HTML 文件的集合,它们只是在 PHP 中加载,而 preg_replace() 用于替换诸如 [var: varName] 或 [var: array|key] 之类的东西或麻烦的东西:[lang: hello]. 这需要用翻译字典中定义的变量替换,该变量存储为 JSON,非程序员也可以编辑。

我无法更改前端或 JSON 文件,并且两者都设计为由非程序员编辑,因此很可能会出现错误、调用不存在的语言变量等。

所以我们可能有 2 个 json 文件,english.json并且french.json

English.json 包含:

{
   "hello":"Hello",
   "bye":"Goodbye"
}

法语.json:

{
"hello": "Bonjour",
"duck": "Canard"
//Plus users can add whatever else they want here and expect to be able to use it in a template
}

有一个模板包含

<b>[lang: hello]</b>

<span>Favourite Animal: [lang:duck]</span>

在这种情况下,如果语言设置为“english”并且正在加载english.json,则应为:

<b>Hello</b>

<span>Favourite Animal: </span>

Or in French:

<b>Bonjour</b>

<span>Favourite Animal: Canard</span>

我们可以假设 json 格式key: value总是string:string但理想情况下我也想处理string: 'T ,但这可能超出了这个问题的范围。

所以我需要转换一个 JSON 文件(由动态名称调用,这给 F# Data 带来了一些我昨晚无法解决的问题,因为它只允许静态文件名作为示例,并且由于这两个文件有可能成为与示例和提供的不同,类型提供程序不起作用)到字典或其他集合。

现在在模板解析函数中,我需要[lang: hello]用类似的东西替换

let key = "duck"

(*Magic function to convert JSON to usable collection*)

let languageString = convertedJSONCollection.[key] (*And obviously check if containsKey first*)

这意味着我需要动态调用密钥,而我不知道如何使用 FSharp.Data 提供的类型来做到这一点。

我也玩过一些透特,以及一些有希望的结果,但最终无济于事。我避免使用 JSON.NET,因为我认为它是付费的,但我意识到我错了,所以可能是探索的途径

为了比较,PHP 函数看起来像这样:

function loadLanguage($lang='english){
    $json = file_get_contents("$lang.json");
    return json_decode($json, true);
}

$key = 'duck';

$langVars = loadLanguage();
$duck = $langVars[$key] || "";

在 F#/.NET 中是否有一种干净的方法可以做到这一点?与 PHP/Javascript 相比,使用 JSON 似乎真的很痛苦,我开始失去理智。我是否必须编写自己的解析器(这意味着可能要回到 PHP)?

向所有知道答案的 F# 天才干杯:p

标签: json.netf#f#-data

解决方案


open Thoth.Json.Net
let deserialiseDictionary (s: string) =
    s
    |> Decode.unsafeFromString (Decode.keyValuePairs Decode.string)
    |> Map.ofList

let printDictionary json =
    json
    |> deserialiseDictionary
    |> fun m -> printfn "%s" m.["hello"] // Hello

对于关于“T”的问题,问题变成了“不可能是什么”?对于 json 它非常有限,它可以是许多东西,字符串、json-object、数字、bool 或 json 数组。如果它是 bool 或 number 会发生什么?


推荐阅读