php - 如何处理来自解析 YAML 锚点的引用?
问题描述
我最近偶然发现了 php's 的一种行为parse_yaml
,其中使用 YAML 中的锚引用定义的部分作为 PHP 数组中的引用返回,给出了这种行为:
$yaml = <<<YAML
a: &foo bar
b: *foo
YAML;
$arr = yaml_parse($yaml);
echo $arr["b"]; // returns "bar" as expected
// but when I update $arr["a"]:
$arr["a"] = "baz";
// $arr["b"] is also updated - because it's a reference!
echo $arr["b"]; // returns "baz"!
这很好,但现在对于我的应用程序,我需要展平这些引用,以便我可以单独更改这些值。
我对此确实有一个不好的解决方案,但是有一个好的解决方案吗?
这是我现在使用的不好的解决方案:
$yaml = <<<YAML
a: &foo bar
b: *foo
YAML;
$arr = yaml_parse(yaml_emit(yaml_parse($yaml))); // yaml_emit doesn't emit anchors/references
$arr["a"] = "baz";
echo $arr["b"]; // returns "bar"
解决方案
如果您的输入在文件中test.yaml
:
a: &foo bar # hello
b: *foo
然后使用以下程序加载和转储该文件,在 YAML 可以展开时展开它(即递归数据不能展平)。
import sys
from pathlib import Path
import ruamel.yaml
def null_op(*args, **kw):
return True
# prevent anchors from being preserved even if there are no aliases for them
ruamel.yaml.comments.CommentedBase.yaml_set_anchor = null_op
ruamel.yaml.scalarstring.ScalarString.yaml_set_anchor = null_op
ruamel.yaml.scalarint.ScalarInt.yaml_set_anchor = null_op
ruamel.yaml.scalarfloat.ScalarFloat.yaml_set_anchor = null_op
ruamel.yaml.scalarbool.ScalarBoolean.yaml_set_anchor = null_op
# backup the original file if not backed up yet
yaml_file = Path('test.yaml')
backup = yaml_file.with_suffix('.yaml.org')
if not backup.exists():
backup.write_bytes(yaml_file.read_bytes())
yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
yaml.representer.ignore_aliases = null_op
data = yaml.load(yaml_file)
yaml.dump(data, yaml_file)
这使:
a: bar # hello
b: bar # hello
替换yaml_set_anchor
方法是必要的,否则您的输出将在具有锚点或别名的地方都有原始锚点。
如您所见,如果您对锚定数据有评论,则会将其复制(并保留原始起始列)。别名后的任何评论都会消失。这不会影响加载数据的语义,应该不是问题。
推荐阅读
- java - 如何在 Mybatis 中为 int[] 类型的 postgres 数据库指定 javaType?
- xml - Spring with XML - 返回列表外的元素
- python - 如何将 Azure Python SDK 异常添加到 try/except 语句?
- azure - 使用 kubectl 在 AKS 集群中创建机密时出错
- sql - 如何在MSSQL中将多行合并为单行
- python - 在 VS Code 笔记本中动画/更新 matplotlib 图
- java - spring 与junit一起使用时的不同行为
- c - 在 C 中传递动态结构后无法写入内存
- java - 此版本中使用了弃用的 Gradle 功能,使其与带有 Minecraft Forge 1.12.2 的 Gradle 5.0 不兼容
- java - 不允许使用数组初始化器(扫雷的副本)