Crystal-lang:递归JSON或哈希

问题描述

我正在尝试创建一个N深度的JSON或哈希。 例: X个具有唯一名称的人可能有Y个孩子,而那些孩子可能有Z个孩子(一直延续到N代)。 我想创建一个看起来像这样的哈希(或JSON):

String url;
var bytes = await new_image.readAsBytes();
try {
    fb.StorageReference _storage = fb.storage().ref('002test');
    fb.UploadTaskSnapshot uploadTaskSnapshot = await _storage.put(bytes,fb.UploadMetadata(contentType: 'image/png')).future;
    var imageUri = await uploadTaskSnapshot.ref.getDownloadURL();
    url = imageUri.toString();
} catch (e) {
    print(e);
}

我尝试使用递归别名,但无法实现。

{
  "John" => {
              "Lara" => { 
                          "Niko" => "Doe"
                        },"Kobe" => "Doe"
            },"Jess" => {
              "Alex" => "Patrik"
            }
}

输入可能来自String之类的数组

alias Person = Hash(String,Person) | Hash(String,String)

(我可以处理这些循环。我的问题是将它们添加到Hash中,因为它们的大小未知。)

我碰到了这个讨论https://forum.crystal-lang.org/t/how-do-i-create-a-nested-hash-type/885,但不幸的是,我无法实现我想要的东西,并且无法保留Hash(或JSON)方法(需要)。

解决方法

我无法完全根据示例输入来得出示例结果,因此我将使用不同的设置:假设我们有一个简单的配置文件格式,其中键通过点分序列和所有值始终都是字符串。

app.name = test
app.mail.enable = true
app.mail.host = mail.local
server.host = localhost
server.port = 3000
log_level = debug

我们可以将其解析为递归Hash,如下所示:

alias ParsedConfig = Hash(String,ParsedConfig)|String

config = Hash(String,ParsedConfig).new

# CONFIG being our input from above
CONFIG.each_line do |entry|
  keys,value = entry.split(" = ")
  keys = keys.split(".")
  current = config
  keys[0..-2].each do |key|
    if current.has_key?(key)
      item = current[key]
      if item.is_a?(Hash)
        current = item
      else
        raise "Malformed config"
      end
    else
      item = Hash(String,ParsedConfig).new
      current[key] = item
      current = item
    end
  end

  current[keys.last] = value
end

pp! config

输出将是:

config # => {"app" =>
  {"name" => "test","mail" => {"enable" => "true","host" => "mail.local"}},"server" => {"host" => "localhost","port" => "3000"},"log_level" => "debug"}

或者,我们可以将其解析为递归结构:

record ConfigGroup,entries = Hash(String,ConfigGroup|String).new

config = ConfigGroup.new

# CONFIG being our input from above
CONFIG.each_line do |entry|
  keys,value = entry.split(" = ")
  keys = keys.split(".")
  current = config
  keys[0..-2].each do |key|
    if current.entries.has_key?(key)
      item = current.entries[key]
      if item.is_a?(ConfigGroup)
        current = item
      else
        raise "Malformed config"
      end
    else
      item = ConfigGroup.new
      current.entries[key] = item
      current = item
    end
  end

  current.entries[keys.last] = value
end

pp! config

输出将是:

config # => ConfigGroup(
 @entries=
  {"app" =>
    ConfigGroup(
     @entries=
      {"name" => "test","mail" =>
        ConfigGroup(@entries={"enable" => "true","host" => "mail.local"})}),"server" => ConfigGroup(@entries={"host" => "localhost","port" => "3000"}),"log_level" => "debug"})

目前,递归结构的bug较少,为解析的域对象上的自定义方法提供了一个不错的地方,并且与递归别名相比,前者通常具有更确定的未来。

carc.in上的完整示例:https://carc.in/#/r/9mxr

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...