当前位置 : 首页 » 文章分类 :  开发  »  YAML

YAML

YAML Ain’t Markup Language
https://yaml.org/

YAML 语言教程 - 阮一峰
http://www.ruanyifeng.com/blog/2016/07/yaml.html


yaml在线编辑/转json

http://www.bejson.com/validators/yaml_editor/


Jackson Dataformat YAML 序列化

内部也使用了 snakeyaml

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.16.0</version>
</dependency>

Jackson 序列化输出 yaml 示例:

YAMLFactory yamlFactory = new YAMLFactory();
yamlFactory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
yamlFactory.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);

ObjectMapper objectMapper = new ObjectMapper(yamlFactory);
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

log.info(objectMapper.writeValueAsString(object));

yamlFactory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES); 字符串不带引号
yamlFactory.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); 去掉开头的 —


SnakeYAML

https://bitbucket.org/snakeyaml/snakeyaml-engine/src/master/

DumperOptions 输出格式选项

FLOW 格式和 BLOCK 格式

DumperOptions.FlowStyle.FLOW:流样式,列表的元素被放在一行内,使用逗号进行分隔。
DumperOptions.FlowStyle.BLOCK:块样式,每个元素占据一行,使用缩进进行分隔。

# 使用流样式
course: [ linux , golang , python ]
- 1, 2, 3

# 使用块样式
course:
- linux
- golang
- python

- 1
- 2
- 3

ScalarStyle 标量格式

{
    "ids": [
        "1.3",
        "1.3.1",
        "1.3.1.1"
    ]
}

转 yaml 后:

ids:
  - '1.3'
  - 1.3.1
  - 1.3.1.1

有的带单引号,有的不带单引号,是因为是否对特殊字符使用引号是由库自行决定的,以确保生成的YAML是有效的。
例如,如果一个字符串中含有在YAML语法中有特殊含义的字符,如冒号、破折号等,SnakeYaml 会自动添加引号以确保字符串被正确解析。
ScalarStyle 可设置为 DOUBLE_QUOTED 表示使所有的字符串都被双引号包围

DumperOptions options = new DumperOptions();
options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
Yaml yaml = new Yaml(options);

设置 Representer Class Tag 删除开头的包名

在使用 SnakeYAML 的 dump() 方法将 Java 对象转换为 YAML 格式时,默认情况下会在输出结果中包含 Java 类的全限定名,即返回第一行的 !!com.package.MyClass
设置 Representer.addClassTag(MyClass.class, Tag.MAP) 可去掉这一行

DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);

Representer representer = new Representer(dumperOptions);
representer.addClassTag(MyClass.class, Tag.MAP);

Yaml yaml = new Yaml(representer, dumperOptions);
return yaml.dump(object);

How to hide bean type in snakeyaml
https://stackoverflow.com/questions/19246027/how-to-hide-bean-type-in-snakeyaml


对象转yaml时自定义yaml字段名

userName 输出为 user_name

TypeDescription typeDescription = new TypeDescription(MyClass.class);
typeDescription.substituteProperty("user_name", String.class, "getUserName", "setUserName");
typeDescription.setExcludes("userName");

Yaml yaml = new Yaml(representer, dumperOptions);
yaml.addTypeDescription(typeDescription);

return yaml.dump(object);

How to serialize fields with custom names using snake yaml in Java
https://stackoverflow.com/questions/54351787/how-to-serialize-fields-with-custom-names-using-snake-yaml-in-java

不太好用,最后直接在输出时定义了一个 Map,手动写死输出的 key 字段名

Map<String, Object> yamlMap = Map.of(
        "user_name", user.getUserName(),
        "user_address", user.getAddress())
);

DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(dumperOptions);
return yaml.dum(yamlMap)

SnakeYaml 锚点和引用(Anchor and Alias, *id001 &id001)

SnakeYaml dump 输出的 yaml 中有 &id001 锚点和 *id001 引用,不方便使用方解析。

- child
  condition: &id001 []
- child
  condition: *id001

原因:
有锚点和引用是因为 SnakeYaml 检测到了完全相同的对象,我这里是空 List。

场景1
因为使用了 Java9 开始添加的 List.of() 构造的空列表,内部是同一个 ImmutableCollections.EMPTY_LIST 空列表对象,改为 Lists.newArrayList() 每次新建一个就好了。

场景2
当 userList 为空时
userList.stream().collect(Collectors.toList()) 每次返回的是一个新的 空list 对象。
userList.stream().toList() 返回的都是相同的 空list 对象。

@Test
public void anchorAndRef() {
    List<String> list = List.of("abc", "dddd", "dfsf");
    Map<String, Object> map = Map.of(
            "toList1", list.stream().filter(s -> s.length() > 10).toList(),
            "toList2", list.stream().filter(s -> s.length() > 10).toList(),
            "collectToList1", list.stream().filter(s -> s.length() > 10).collect(Collectors.toList()),
            "collectToList2", list.stream().filter(s -> s.length() > 10).collect(Collectors.toList())
    );
    Yaml yaml = new Yaml();
    log.info("\n{}", yaml.dumpAsMap(map));
}

结果:

toList2: &id001 []
toList1: *id001
collectToList2: []
collectToList1: []

YAML Anchors And Aliases And How To Disable Them
https://ttl255.com/yaml-anchors-and-aliases-and-how-to-disable-them/

Java SnakeYaml - prevent dumping reference names
https://stackoverflow.com/questions/18202548/java-snakeyaml-prevent-dumping-reference-names


YAML 语法

基本语法

单一文件第一行,使用连续三个连字号 - 表示开始
‘#’ 表示注释
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
键值对之间需要加一个空格来隔开 比如: key: value

yaml中的3种数据类型

标量/纯量(scalar):单个的、不可再分的值
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)


字符串

yaml 中的字符串加不加引号效果都是一样的(相对的,JSON中字符串必须加双引号)

多行字符串

字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。

str: 这是一段
  多行
  字符串

转成json是

{
    "str": "这是一段 多行 字符串"
}

| 竖线保留换行符

this: |
  Foo
  Bar

对应 json

{
    "this": "Foo\nBar\n"
}

|+ 保留末尾换行

|- 删除末尾换行

s1: |
  Foo

s2: |+
  Foo


s3: |-
  Foo

对应 json

{
  "s1": "Foo\n",
  "s2": "Foo\n\n\n",
  "s3": "Foo"
}

>大于号折叠换行

that: >
  Foo
  Bar

转为 json

{
    "that": "Foo Bar\n"
}

对象

字典:也叫做对象,多个键值对的组合
字典由多个key与value构成,value可以是标量,也可以是字典或者列表
key和value之间用 :分隔, 并且 : 后面有一个空格,
所有k/v可以放在一行,或者每个 k/v 分别放在不同行

account: { name: wang, age: 30 }

# 或者

account:
  name: wang
  age: 18

数组

放在同一行:用中括号括起来,多个元素逗号隔开

course: [ linux , golang , python ]

每个元素放在不同行,且元素前均使用”-“打头,并且 - 后有一个空格

course:
- linux
- golang
- python

yaml示例

#我是对象。。。顺便说一下注释是#
 animal: pets
 #注意:1.冒号后必须有空格
      #2.可以将键值对写成一个行内对象
      #3.空格标识层级关系
 hash: {name: Stave, foo: bar }
 #我是数组
 type:
  - Cat
  - Dog
  - Goldfish
 Dog:
 - big dog
 - small dog

 #我是纯量、最基本不可分
    #数值型
 number: 11.11
    #布尔类型
 isBeautiful: true
    #时间采用
 time: 20:41:58
    #日期
 date: 2018-7-9
    #字符串
 str0: '我是字符串'
 str1: "我是双引号,单引号和双引号没有区别,不会对特殊字符转义"
 str2: 'It''s a test,单引号中如果有单引号的字符,需要转义'
 str3: ~  #~是空的意思
 str4: !!str true '两个!表示强制转换'
 str5: 我也可以不用引号引起来,厉害不
 str6: '但是有空格 或者 特殊字符* 我就必须放在引号中了'
 str7: 字符串可以换行
  像这样
  每换一行都要有空格标记,换行符会被转义为空格
 #否则就报错,只能被注释了!!!!惨兮兮
 str8: |
    我不是一般的竖线,我是可以保留换行符的竖线
 str9: >
    我是
    可以折叠换行
    的大于号
 str10: |-
  我不想要末尾的换行符
 str11: |+
  我又想要末尾的换行符了,后面跟了一串尾巴
 str12:
  <p style="color:red">Hello world<p>

转成 json

{
  "animal": "pets",
  "hash": {
    "name": "Stave",
    "foo": "bar"
  },
  "type": [
    "Cat",
    "Dog",
    "Goldfish"
  ],
  "Dog": [
    "big dog",
    "small dog"
  ],
  "number": 11.11,
  "isBeautiful": true,
  "time": 74518,
  "date": "2018-7-9",
  "str0": "我是字符串",
  "str1": "我是双引号,单引号和双引号没有区别,不会对特殊字符转义",
  "str2": "It's a test,单引号中如果有单引号的字符,需要转义",
  "str3": null,
  "str4": "true '两个!表示强制转换'",
  "str5": "我也可以不用引号引起来,厉害不",
  "str6": "但是有空格 或者 特殊字符* 我就必须放在引号中了",
  "str7": "字符串可以换行 像这样 每换一行都要有空格标记,换行符会被转义为空格",
  "str8": "我不是一般的竖线,我是可以保留换行符的竖线\n",
  "str9": "我是 可以折叠换行 的大于号\n",
  "str10": "我不想要末尾的换行符",
  "str11": "我又想要末尾的换行符了,后面跟了一串尾巴\n",
  "str12": "<p style=\"color:red\">Hello world<p>"
}

上一篇 2021年运动记录

下一篇 护肤

阅读
评论
2.2k
阅读预计9分钟
创建日期 2020-11-06
修改日期 2024-03-12
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论