【问题标题】:Convert yaml strings to JSON objects将 yaml 字符串转换为 JSON 对象
【发布时间】:2020-01-20 16:32:45
【问题描述】:

我们有两个独立的代码库,它们使用不同的本地化风格。其中一个代码库使用 yaml,另一个使用 JSON。

现在,我们正在慢慢迁移到使用 JSON 的代码库,但是使用 20k yaml 字符串和 7 种不同的语言,手动转换这一切是一件很痛苦的事情。不幸的是,我们在 yaml 文件中使用的是字符串表示法而不是对象表示法,因此像 this 这样的转换器将无法工作。

示例 yaml

cart.title.primary: Cart
cart.title.secondary: Buy products
cart.dialog.title: Remove product
cart.dialog.text: Are you sure to remove this product?

变成转换器这个

{
  "cart.title.primary": "Cart",
  "cart.title.secondary": "Buy products",
  "cart.dialog.title": "Remove product",
  "cart.dialog.text": "Are you sure to remove this product?"
}

但我想要的是字符串中的每个点实际上是 JSON 中的一个对象。所以理想情况下,我提供的 yaml 应该是这样的:

{
  "cart": {
    "title": {
      "primary": "Cart",
      "secondary: "Buy Products"
    },
    "dialog": {
      "title": "Remove product",
      "text": "Are you sure to remove this product?"
    }
  }
}

有没有做过类似事情的人?首选。使用 PHP 或 JavaScript。提前致谢!

【问题讨论】:

    标签: javascript php json yaml


    【解决方案1】:

    您可以结合使用 yaml 的基本加载,这只是假设一个字符串并使用 yaml_parse(),然后使用来自 Convert dot syntax like "this.that.other" to multi-dimensional array in PHP 的代码,您可以一次处理每一行以创建新结构...

    $yaml = 'cart.title.primary: Cart
    cart.title.secondary: Buy products
    cart.dialog.title: Remove product
    cart.dialog.text: Are you sure to remove this product?';
    
    $data = yaml_parse($yaml);
    
    $output = [];
    foreach ( $data as $key => $entry ) {
        assignArrayByPath($output, $key, $entry);
    }
    
    function assignArrayByPath(&$arr, $path, $value, $separator='.') {
        $keys = explode($separator, $path);
    
        foreach ($keys as $key) {
            $arr = &$arr[$key];
        }
    
        $arr = $value;
    }
    
    echo json_encode($output, JSON_PRETTY_PRINT);
    

    给你

    {
        "cart": {
            "title": {
                "primary": "Cart",
                "secondary": "Buy products"
            },
            "dialog": {
                "title": "Remove product",
                "text": "Are you sure to remove this product?"
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      作为 Node.js 脚本:

      #!/usr/bin/env node
      
      const fs = require('fs')
      
      var file = process.argv[process.argv.length - 1]
      var json = {}
      fs.readFileSync(file, { encoding: 'utf8' })
        .split(/\r?\n/)
        .forEach((line) => {
          [keyPath, value] = line.split(/: */)
          var target = json
          var keys = keyPath.split(/\./)
          var counter = 0
          keys.forEach((key) => {
            counter++
            if (counter === keys.length) target[key] = value
            else {
              if (!(key in target)) target[key] = {}
              target = target[key]
            }
          })
        })
      console.log(JSON.stringify(json, null, 2))
      

      使用它:

      convert.js file.yaml
      

      输出,使用您的 example.yaml 作为输入:

      {
        "cart": {
          "title": {
            "primary": "Cart",
            "secondary": "Buy products"
          },
          "dialog": {
            "title": "Remove product",
            "text": "Are you sure to remove this product?"
          }
        }
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用split 方法构建此嵌套结构,从键创建路径数组,然后使用reduce 方法基于该键数组嵌套属性。

        const yaml = {
          "cart.title.primary": "Cart",
          "cart.title.secondary": "Buy products",
          "cart.dialog.title": "Remove product",
          "cart.dialog.text": "Are you sure to remove this product?"
        }
        
        const toJson = (data) => {
          return Object.keys(data).reduce((a, k) => {
            k.split('.').reduce((r, e, i, a) => {
              return r[e] || (r[e] = (a[i + 1] ? {} : data[k]))
            }, a)
            return a
          }, {})
        }
        
        console.log(toJson(yaml))

        您也可以使用split 方法将yaml 字符串拆分为新行,然后使用reduce 构建嵌套对象。

        const yaml = `
        cart.title.primary: Cart
        cart.title.secondary: Buy products
        cart.dialog.title: Remove product
        cart.dialog.text: Are you sure to remove this product?
        `
        const obj = yaml.split('\n').filter(Boolean).reduce((a, k) => {
          const [key, value] = k.split(': ')
        
          key.split('.').reduce((r, e, i, arr) => {
            return r[e] || (r[e] = (arr[i + 1] ? {} : value))
          }, a)
        
          return a;
        }, {})
        
        console.log(obj)

        【讨论】:

          猜你喜欢
          • 2019-08-27
          • 2020-05-27
          • 1970-01-01
          • 1970-01-01
          • 2011-04-23
          • 2012-06-14
          • 2012-02-20
          • 2015-01-03
          相关资源
          最近更新 更多