【问题标题】:How to compress a YAML file using references in a script?如何使用脚本中的引用压缩 YAML 文件?
【发布时间】:2019-09-12 09:59:42
【问题描述】:

我正在使用 safeDump 将 json 文件转换为带有 https://github.com/nodeca/js-yaml 的 YAML 文件

结果是这样的

en:
  models: 
    errors:
      name: name not found
      url: bad url
  user: 
    errors:
      name: name not found
      url: bad url
  photo:
    errors:
      name: name not found
      url: bad url

但我想要一个脚本来压缩引用

en:
  models: 
    errors: &1
      name: name not found
      url: bad url
  user:
    errors: *1
  photo:
    errors: *1

【问题讨论】:

标签: javascript yaml


【解决方案1】:

基于来自Anthonhttps://stackoverflow.com/a/55808583/10103951的Python脚本

function buildRefsJson(inputJson, mappings = null) {
if (!mappings) {
    mappings = {}
}
if (typeof(inputJson) === 'object') {
    let value
    let stringValue
    let ref
    for (let key in inputJson) {
        value = inputJson[key]
        stringValue = JSON.stringify(value)
        ref = mappings[stringValue]
        if (ref) {
            inputJson[key] = ref
        } else {
            mappings[stringValue] = value
            buildRefsJson(inputJson[key], mappings)
        }
    }
}

我将其转换为 JavaScript 代码。它完成了工作!也感谢Niroj 的帮助

【讨论】:

    【解决方案2】:

    您想要做的是将 JSON 输入“压缩”到 YAML 并引用那些映射 具有完全相同的键值对。为了实现这一目标,您需要能够找到 这种匹配映射和一种方法是通过创建一个基于 对键排序后的映射字符串表示。

    假设这个 JSON 输入在 input.json:

    {
      "en": {
        "models": {
          "errors": {
            "name": "name not found",
            "url": "bad url"
          }
        },
        "user": {
          "errors": {
            "name": "name not found",
            "url": "bad url"
          }
        },
        "photo": {
          "errors": {
            "name": "name not found",
            "url": "bad url"
          }
        }
      }
    }
    

    您可以使用此 Python 脚本将其转换为:

    import json
    import sys
    from pathlib import Path
    import ruamel.yaml
    
    in_file = Path('input.json')
    
    
    def optmap(d, mappings=None):
        if mappings is None:
            mappings = {}
        if isinstance(d, dict):
            for k in d:
                v = d[k]
                sv = repr(v)
                ref = mappings.get(sv)
                if ref is not None:
                    d[k] = ref
                else:
                    mappings[sv] = v
                    optmap(d[k], mappings)     
        elif isinstance(d, list):
            for idx, item in d:
                sitem = repr(item)
                ref = mappings.get(sitem)
                if ref is not None:
                    d[idx] = sitem
                else:
                    mappings[sitem] = item
                    optmap(item, mappings)
    
    
    data = json.load(in_file.open())
    optmap(data)
    yaml = ruamel.yaml.YAML()
    yaml.serializer.ANCHOR_TEMPLATE = u'%d'
    yaml.dump(data, sys.stdout)
    

    给出:

    en:
      models: &1
        errors:
          name: name not found
          url: bad url
      user: *1
      photo: *1
    

    上面还将引用和遍历 JSON 中的数组。

    如您所见,您的输出可能会比实际情况更“压缩”。


    我的 JavaScript 不够流利,无法用该语言编写此答案(无需投入太多精力并提供一些丑陋的代码),但 OP 显然理解 optmap() 的意图并在 his answer 中实现了它/p>

    【讨论】:

      【解决方案3】:

      遗憾的是,据我所知,没有将 JSON 转换为带有引用的 YML 的解决方案,因为在 JSON 中没有用于重复节点的“引用”规则。正如spec 所说,YAML 因此可以被视为 JSON 的自然超集。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-01
        • 1970-01-01
        相关资源
        最近更新 更多