如何使用SnakeYaml底层API(如getAsInt)解析YAML?是否支持类GSON的API?
使用SnakeYaml的底层API实现类似Gson
getAsInt的解析 当然支持!SnakeYaml其实提供了一套底层的节点解析API,完全可以摆脱Java类绑定,实现像Gson getAsInt 那样灵活的按需取值操作。下面我给你具体拆解怎么用:
核心思路:直接操作Node节点
SnakeYaml的底层解析会把YAML内容转换成不同类型的Node对象(比如标量节点ScalarNode、映射节点MappingNode、序列节点SequenceNode),我们可以直接对这些节点进行类型判断和值提取,完全不用提前定义Java实体类。
具体步骤与代码示例
1. 获取根节点
首先通过Yaml加载YAML内容,拿到根节点:
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.ScalarNode; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.SequenceNode; public class SnakeYamlLowLevelDemo { public static void main(String[] args) { String yamlContent = """ user: id: 123 name: Alice scores: [90, 85, 95] """; // 初始化Yaml实例 Yaml yaml = new Yaml(); // 加载并获取根节点 Node rootNode = yaml.getConstructor().getSingleNode(yaml.loadAs(yamlContent, Object.class)); } }
2. 提取映射节点中的int值(类似getAsInt)
假设我们要获取user.id的int值,可以这样操作:
// 根节点是MappingNode(对应YAML的键值对) if (rootNode instanceof MappingNode rootMapping) { // 根据key找到对应的子节点 Node userNode = rootMapping.getValue().stream() .filter(entry -> ((ScalarNode) entry.getKeyNode()).getValue().equals("user")) .map(entry -> entry.getValueNode()) .findFirst() .orElseThrow(() -> new IllegalArgumentException("user节点不存在")); // user节点也是MappingNode,继续找id节点 if (userNode instanceof MappingNode userMapping) { Node idNode = userMapping.getValue().stream() .filter(entry -> ((ScalarNode) entry.getKeyNode()).getValue().equals("id")) .map(entry -> entry.getValueNode()) .findFirst() .orElseThrow(() -> new IllegalArgumentException("id节点不存在")); // id节点是ScalarNode,转成int值 if (idNode instanceof ScalarNode idScalar) { int userId = Integer.parseInt(idScalar.getValue()); System.out.println("用户ID:" + userId); // 输出123 } } }
3. 简化封装(模拟getAsInt)
如果觉得每次写流式查找太麻烦,可以封装一个工具方法,类似Gson的getAsInt:
private static int getAsInt(MappingNode mappingNode, String key) { Node targetNode = mappingNode.getValue().stream() .filter(entry -> ((ScalarNode) entry.getKeyNode()).getValue().equals(key)) .map(entry -> entry.getValueNode()) .findFirst() .orElseThrow(() -> new IllegalArgumentException(key + "节点不存在")); if (!(targetNode instanceof ScalarNode scalarNode)) { throw new IllegalArgumentException(key + "不是标量节点"); } return Integer.parseInt(scalarNode.getValue()); }
调用的时候就简洁多了:
int userId = getAsInt(userMapping, "id");
4. 处理序列节点(数组/列表)
如果要提取scores中的int值,也可以用类似的方式:
Node scoresNode = userMapping.getValue().stream() .filter(entry -> ((ScalarNode) entry.getKeyNode()).getValue().equals("scores")) .map(entry -> entry.getValueNode()) .findFirst() .orElseThrow(() -> new IllegalArgumentException("scores节点不存在")); if (scoresNode instanceof SequenceNode scoresSequence) { scoresSequence.getValue().forEach(node -> { if (node instanceof ScalarNode scoreScalar) { int score = Integer.parseInt(scoreScalar.getValue()); System.out.println("分数:" + score); } }); }
注意事项
- 要注意节点类型的判断,避免类型转换异常
- 如果YAML中有非字符串的标量(比如直接写数字
id: 123),ScalarNode.getValue()会返回字符串形式的"123",需要自己转成对应类型 - 对于复杂的YAML结构,可以递归处理节点
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

