javascript - 无法将 YAML 与注释合并

标签 javascript json node.js xml yaml

我正在开发一个工具来自动化一些工作,我需要将一些配置 YAML 合并到一个中,但我需要注释,因为我需要向 future 描述这些字段。
我已经成功地在没有注释的情况下做到了这一点,将 YAML 转换为 JSON,再次合并并转换为 YAML。我愿意使用 XML 或其他东西,因为我可以在本地运行它。有人知道可以帮助我吗?

像这样:

文件 1

project:
    general:
        environment: ?

    databases:
        # Main Database
        db1:
            host: localhost
            username: root
            password: root123
            dbname: project
            logFile: ?

文件 2:

project:
    general:
        environment: local

    databases:
        db1:
            # New Log File
            logFile: project.log

会导致这样的结果:

project:
    general:
        environment: local

    databases:
        # Main Database
        db1:
            host: localhost
            username: root
            password: root123
            dbname: project
            # New Log File
            logFile: project.log

最佳答案

正如 @flyx 所指出的,您应该查看 ruamel.yaml 的往返功能(免责声明:我是该包的作者),尽管没有内置的递归合并并且有一些警告。

首先,您应该引用您的 ? 值,否则您会收到一条警告,指出不允许映射键(因为普通的 ? 通常会引入显式定义的映射键)。

还需要了解的是,ruamel.yaml 中的注释关联往往与注释之前的最后一个解析 Node 相​​关联。因此,在您的 file2.yaml 中,# New Log File 注释与前面的键 db1 关联,而不是与下面的 logFile

如果您愿意像这样输入file1.yaml:

project:
    general:
        environment: '?'

    databases:
        # Main Database
        db1:
            host: localhost
            username: root
            password: root123
            dbname: project
            logFile: '?'

file2.yaml如:

project:
    general:
        environment: local

    databases:
        db1:
            logFile: project.log   # New Log File

然后这个程序:

import sys
from pathlib import Path
import ruamel.yaml


def update(d, n):
    if isinstance(n, ruamel.yaml.comments.CommentedMap):
        for k in n:
            d[k] = update(d[k], n[k]) if k in d else n[k]
            if k in n.ca._items and n.ca._items[k][2] and \
               n.ca._items[k][2].value.strip():
                d.ca._items[k] = n.ca._items[k]  # copy non-empty comment
    else:
        d = n
    return d

data1 = ruamel.yaml.round_trip_load(Path('file1.yaml').read_text())
update(data1, ruamel.yaml.round_trip_load(Path('file2.yaml').read_text()))
ruamel.yaml.round_trip_dump(data1, sys.stdout)

足以为您提供以下输出:

project:
  general:
    environment: local

  databases:
        # Main Database
    db1:
      host: localhost
      username: root
      password: root123
      dbname: project
      logFile: project.log         # New Log File

请注意,logFile: '?' 不必位于 file1.txt 中,因为缺少的键将添加到映射末尾。

如果将# New Log File移动到 key 后面的位置 Not Acceptable ,那么您必须预处理从file2.yaml加载的数据,在这种情况下这并不困难。这样做是基于例如取决于原始 file2.yaml 中的缩进是可能的,但需要更多行代码才能正确,并且有点脆弱:

import sys
from pathlib import Path
import ruamel.yaml

INDENT=4

def update(d, n):
    if isinstance(n, ruamel.yaml.comments.CommentedMap):
        for k in n:
            d[k] = update(d[k], n[k]) if k in d else n[k]
            if k in n.ca._items and \
               ((n.ca._items[k][2] and n.ca._items[k][2].value.strip()) or \
                n.ca._items[k][1]):
                d.ca._items[k] = n.ca._items[k]  # copy non-empty comment
    else:
        d = n
    return d


def move_comment(d, depth=0):
    # recursively adjust comment
    if isinstance(d, ruamel.yaml.comments.CommentedMap):
        for k in d:
            if isinstance(d[k], ruamel.yaml.comments.CommentedMap):
                if hasattr(d, 'ca'):
                    comment = d.ca.items.get(k)
                    if comment and comment[3] is not None:
                        # add to first key of the mapping that is the value
                        for k1 in d[k]:
                            d[k].yaml_set_comment_before_after_key(
                                k1,
                                before=comment[3][0].value.lstrip('#').strip(),
                                indent=INDENT*(depth+1))
                            break
            move_comment(d[k], depth+1)
    return d

data1 = ruamel.yaml.round_trip_load(Path('file1.yaml').read_text())
update(data1, move_comment(ruamel.yaml.round_trip_load(Path('file2.yaml').read_text())))
ruamel.yaml.round_trip_dump(data1, sys.stdout, indent=INDENT)

上面的内容准确地给出了您要求的输出,其中包括更正后的 ('?') file1.yaml 和原始 file2.yaml.

关于javascript - 无法将 YAML 与注释合并,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43592168/

相关文章:

javascript - 如何在超过超时时阻止 NodeJS 脚本崩溃

html - 多人 HTML5、Node.js、Socket.IO

javascript - 在 Javascript 中使用 Google People API 获取联系电子邮件地址

php - 使用ajax和php的投票系统

javascript:如何处理Json中的 "@"和 ":"

java - 如何在 Eclipse 中导入 JSON Simple?

javascript - ExpressJS 链 promise 多次调用 next() 函数

javascript - R Shiny-为电缆表添加额外的标题行 'sticky'

javascript - 如何创建 GUID/UUID?

javascript - 使用 JSON.parse() 检索本地存储数组列表