1. 概述
YAML(YAML Ain’t Markup Language)是一种常用于配置文件的可读性数据格式。官方 Kotlin 序列化库 kotlinx-serialization 并未直接支持 YAML 格式。不过社区提供了如 kaml 和 YamlKt 这类库,它们基于 kotlinx-serialization 实现了对 YAML 的支持。
本文将重点讲解如何在 Kotlin 中 反序列化 YAML 内容,包括标量值、列表、映射以及自定义对象的解析。
2. 依赖配置
首先,我们需要在项目中引入相关依赖。
kaml 依赖:
<dependency>
<groupId>com.charleskorn.kaml</groupId>
<artifactId>kaml-jvm</artifactId>
<version>0.58.0</version>
</dependency>
YamlKt 依赖:
<dependency>
<groupId>net.mamoe.yamlkt</groupId>
<artifactId>yamlkt-jvm</artifactId>
<version>0.13.0</version>
</dependency>
此外,还需要在 pom.xml
中启用 Kotlin 序列化插件:
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>kotlinx-serialization</plugin>
</compilerPlugins>
</configuration>
</plugin>
</plugins>
</build>
✅ 注意:确保所有库版本兼容,避免运行时异常。
3. 读取标量值(Scalar Values)
YAML 中最简单的数据类型是标量值,包括字符串、数字、布尔值和空值。
3.1. 使用 kaml
初始化 Yaml
实例:
val yamlDefault = com.charleskorn.kaml.Yaml.default
使用 decodeFromString()
解析字符串:
val scalarStringYamlStr = "Hello!"
val parsedData: String = yamlDefault.decodeFromString(scalarStringYamlStr)
assertEquals("Hello!", parsedData)
或使用 parseToYamlNode()
提取 YamlScalar
:
val parsedData: YamlScalar = yamlDefault.parseToYamlNode(scalarStringYamlStr).yamlScalar
assertEquals("Hello!", parsedData.content)
3.2. 使用 YamlKt
初始化默认配置:
val yamlDefault = net.mamoe.yamlkt.Yaml.Default
同样使用 decodeFromString()
:
val parsedData: String = yamlDefault.decodeFromString(scalarStringYamlStr)
assertEquals("Hello!", parsedData)
⚠️ 注意:两个库的 Yaml
类实现不同,不要混淆使用。
4. 读取列表(Lists)
YAML 支持块风格(block style)和流风格(flow style)两种列表格式。
4.1. 块风格 vs 流风格
val numberListYamlStr =
"""
- 123
- 456
"""
val numberListYamlStr = "[123,456]"
建议使用块风格处理长列表,流风格适用于短列表。
4.2. 使用 kaml
val parsedData: List<Int> = yamlDefault.decodeFromString(numberListYamlStr)
assertEquals(listOf(123, 456), parsedData)
也可以解析为 YamlList
:
val parsedData: YamlList = yamlDefault.parseToYamlNode(numberListYamlStr).yamlList
assertEquals(123, parsedData[0].yamlScalar.content.toInt())
4.3. 使用 YamlKt
支持 decodeListFromString()
方法:
val parsedData: List<Any?> = yamlDefault.decodeListFromString(numberListYamlStr)
assertEquals(listOf(123, 456), parsedData)
5. 读取映射(Maps)
YAML 中的映射是键值对结构。
5.1. 使用 kaml
解析为 YamlMap
:
val mapWithScalarValuesYamlStr =
"""
k1: v1
k2: 123
k3: false
k4: 12.3
k5: 1.2e1
k6: ~
"""
val yamlMapNode: YamlMap = yamlDefault.parseToYamlNode(mapWithScalarValuesYamlStr).yamlMap
验证值:
assertEquals("v1", yamlMapNode.getScalar("k1")!!.content)
assertEquals(123, yamlMapNode.getScalar("k2")!!.toInt())
assertTrue(yamlMapNode.get<YamlNode>("k6")!! is YamlNull)
5.2. 使用 YamlKt
可直接解析为 YamlMap
:
val parsedData: YamlMap = yamlDefault.decodeFromString(mapWithScalarValuesYamlStr)
assertEquals("v1", parsedData.getString("k1"))
也可解析为 Kotlin Map
:
val parsedData: Map<String?, Any?> = yamlDefault.decodeMapFromString(mapWithScalarValuesYamlStr)
assertEquals(12.3, parsedData["k4"])
6. 使用自定义 Schema 解析
6.1. YAML 文档和数据类定义
示例 users.yaml
:
users:
- name: Alice
age: 30
address:
city: New York
country: USA
- name: Bob
age: 35
address:
city: London
country: UK
定义数据类:
@Serializable
data class Address(val city: String, val country: String)
@Serializable
data class User(val name: String, val age: Int, val address: Address)
@Serializable
data class Users(val users: List<User>)
6.2. 验证函数 verifyUsers()
fun verifyUsers(users: Users) {
assertNotNull(users)
val user1 = users.users[0]
assertEquals("Alice", user1.name)
assertEquals("USA", user1.address.country)
}
6.3. 使用 kaml 解析
fun getUsersUsingUsersSerializer(fileContent: String): Users {
val yaml = Yaml(configuration = YamlConfiguration(strictMode = false))
return yaml.decodeFromString(fileContent)
}
调用验证:
val users = getUsersUsingUsersSerializer(fileContent)
verifyUsers(users)
6.4. 使用 YamlKt 解析
fun getUsersUsingUsersSerializer(fileContent: String): Users {
return Yaml.Default.decodeFromString(Users.serializer(), fileContent)
}
验证结果:
val users = getUsersUsingUsersSerializer(fileContent)
verifyUsers(users)
7. 总结
本文介绍了如何使用 kaml 和 YamlKt 两个库在 Kotlin 中读取 YAML 内容,涵盖了:
- 标量值、列表、映射的解析
- 自定义数据类的反序列化
- 不同库的 API 使用方式
两个库各有优势,选择时可根据项目需求和社区活跃度决定。
完整代码可在 GitHub 仓库 找到。
✅ 建议:使用时注意版本兼容性,并合理使用类型安全处理方式,避免运行时异常。