Как сжать файл YAML, используя ссылки в скрипте? - PullRequest
2 голосов
/ 23 апреля 2019

Я конвертирую json-файл в YAML-файл с https://github.com/nodeca/js-yaml, используя safeDump

Результат такой:

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

Ответы [ 3 ]

1 голос
/ 23 апреля 2019

На основе сценария Python от Anthon https://stackoverflow.com/a/55808583/10103951

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 за помощь

0 голосов
/ 23 апреля 2019

То, что вы хотите сделать, это "сжать" входные данные JSON в YAML со ссылками на те сопоставления, которые имеют точно такие же пары ключ-значение.Чтобы достичь этого, вам нужно найти такие сопоставления и один из способов сделать это - создать таблицу подстановки на основе строкового представления сопоставления после сортировки ключей .

*.1004 * Предполагая этот ввод 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, чтобы написать этот ответ на этом языке (не вкладывая слишком много усилий и не доставив некрасивого кода), но ОП, очевидно, понял намерение optmap() и реализовал его в своего ответа

0 голосов
/ 23 апреля 2019

К сожалению, нет решения для преобразования JSON в YML со ссылками, насколько я знаю, потому что нет такого правила "ссылок" для повторяющихся узлов в JSON. Как говорит spec , YAML можно рассматривать как естественный суперсет JSON.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...