在不知道完整结构的情况下反序列化 JSON

Deserialize JSON without knowing full structure

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

开始了。

前端基本上是 HTML 文件的集合,这些文件只是在 PHP 中加载, preg_replace() 用于替换 [var: varName] 或 [ var: array|key] 或麻烦的一个:[lang: hello]。这需要用翻译词典中定义的变量替换,该变量存储为 JSON,非程序员也可编辑。

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

所以我们可能有 2 个 json 文件,english.jsonfrench.json

english.json 包含:

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

french.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.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 提供的类型来实现。

我也尝试过一些 Thoth 以及一些有希望的结果,但最终无处可去。我避免了 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

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 的问题,问题变成了'T 可以是什么?对于 json 它非常有限,它可以是一些东西,字符串,json-object,数字,bool 或者 json 数组。如果是 bool 或 number 会怎样?