Java中如何使用SnakeYaml安全提取YAML文件嵌套值
实现方案
你当前的循环思路只处理了第一层Map结构,遇到多层嵌套、根节点为列表的场景会失效,且直接使用默认Yaml构造器加载未知文件存在安全风险,可通过递归遍历+安全加载的方式实现任意结构YAML的嵌套值提取,具体实现如下:
安全加载说明
SnakeYAML默认构造器支持将YAML标签反序列化为任意Java对象,加载未知来源文件时存在远程代码执行漏洞,解析前必须配置SafeConstructor禁用危险的反序列化能力。
可直接运行的实现代码
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.apache.commons.io.FileUtils; import java.io.File; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; public class UniversalYamlParser { public static void main(String[] args) throws Exception { File targetYamlFile = new File("path/to/your/file.yaml"); // 初始化安全解析实例,禁止任意类反序列化 Yaml yaml = new Yaml(new SafeConstructor()); // 加载结果统一用Object接收,避免根节点为List时强转报错 Object rootNode = yaml.load(FileUtils.readFileToString(targetYamlFile, StandardCharsets.UTF_8)); // 从根节点开始递归遍历,初始路径为空 traverseNestedNode("", rootNode); } /** * 递归遍历任意深度的YAML节点,自动识别Map、List、基础值类型 * @param currentPath 当前节点的完整层级路径,如datasource.url、user[0].name * @param node 当前待处理的节点对象 */ private static void traverseNestedNode(String currentPath, Object node) { // 处理空值 if (node == null) { System.out.printf("路径:%s | 值:null%n", currentPath); return; } // 节点为键值对结构,递归遍历每个子键 if (node instanceof Map<?, ?> mapNode) { for (Map.Entry<?, ?> entry : mapNode.entrySet()) { String nodeKey = entry.getKey().toString(); String childPath = currentPath.isEmpty() ? nodeKey : currentPath + "." + nodeKey; traverseNestedNode(childPath, entry.getValue()); } return; } // 节点为列表/数组结构,按索引遍历每个元素 if (node instanceof List<?> listNode) { for (int index = 0; index < listNode.size(); index++) { String childPath = currentPath + "[" + index + "]"; traverseNestedNode(childPath, listNode.get(index)); } return; } // 节点为基础类型(字符串、数字、布尔值等),直接输出/存储值 System.out.printf("路径:%s | 值:%s | 值类型:%s%n", currentPath, node, node.getClass().getSimpleName()); } }
适配说明
- 如果你使用的是Java 16以下版本,将代码中
instanceof Map<?, ?> mapNode、instanceof List<?> listNode的模式匹配写法改为传统类型判断+手动强转即可,核心遍历逻辑不需要修改。 - 原有代码中
StrandardCharsets为拼写错误,JDK提供的标准字符集类正确名为StandardCharsets。 - 如果需要按指定路径提取值(比如提取
server.port对应的值),只需要在遍历到基础值节点时判断currentPath是否和目标路径匹配即可,不需要提前预知YAML的整体结构。 - 该实现会自动处理任意嵌套深度,不需要手动写多层循环,也不会漏掉列表类型的嵌套节点。
内容的提问来源于stack exchange,提问作者AwesomeDude091
相关产品推荐
相关产品推荐

