首页 > 解决方案 > 在 YAML 嵌套数据中搜索值

问题描述

我目前正在尝试将 YAML 文件解析为输入/配置以运行某些测试。问题是:使用杰克逊,无论我为它设计的结构如何,嵌套数据似乎都不适合这个类,几乎每次我得到这样的东西:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token

我打算使用与 XPath 类似的方法简单地“搜索” YAML 文件中的数据,而不用担心映射对象和有限级别的嵌套。

这是示例类:

public class YAMLInput {

    private ArrayList<SomeContainer> containers;
    //getter and setters

    private class SomeContainer {
        private String name; 
        private String path;
        private ArrayList<Integer> intList;
        private ArrayList<String> strList;
        private ArrayList<SomeObject> someObjList;

        private class SomeObject {
             private String objectName;
             private ArrayList<String> strList;
        }

    }
}

Yaml 输入:

container:
    name: Cont1
    path: /storage/outputFolder
    intList: 
        - 100
        - 200
        - 300
    strList:
        - strFirst
        - strSecond
        - strThird
    someObjList: 
        obj1: 
          objName: strname
          strList: 
             - 100
             - 200
             - 300
        obj2:
          # (...)

这个想法是为YAMLInput类构建一个构造函数:

public YAMLInput( SearchableYAMLData data) {
   for(SearchableYAMLData container : data.getList("container")){
      this.containers.add( new SomeContainer());
      this.containers.get(0) = container.get("name");
      //...
   }
}

最接近这个假设SearchableYAMLData类的可用工具是什么?

标签: javaxpathjacksonyamlsnakeyaml

解决方案


您得到的错误可能源于您显示的 YAML 与您显示的类不对应。someObjList在您的 YAML 数据中是一个映射(包含键值对,第一个键是obj1),而在您的类中,它是一个ArrayList<SomeObject>. 这对应于您的 YAML 数据中的一个序列,应该如下所示:

someObjList: 
    - objName: strname
      strList: 
         - 100
         - 200
         - 300
    - # (...)

但是,我不确定,因为您并没有真正显示产生错误的代码。

话虽如此,如果您正在寻找一种通过任意 YAML 进行搜索的方法,请不要使用 Jackson。Jackson 是一个(反)序列化的工具,你不想反序列化你的 YAML;你只想走它的结构。为此,您可以使用 SnakeYAML,它是 Jackson 使用的 YAML 解析器:

Yaml yaml = new Yaml();
Node root = yaml.compose(new StringReader("foo: bar"));

root将是 a ScalarNode、 aMappingNode或 a SequenceNode。后两个将包含您可以下降的子节点。这种结构对于类似 XPath 的搜索当然是可行的。

如果您追求性能,更快的方法是使用parseSnakeYaml 的顺序接口。基本上,您不断地从解析器中查询下一个事件并检查您正在搜索的路径是否包含它。如果是这样,继续查询它的子元素并在那里搜索路径中的下一个元素。如果没有,解析并转储当前事件的所有子内容,然后继续搜索当前路径元素。

如果您可以阅读 Python,您可以从我的回答中获得一些灵感,该回答通过事件解析输入 YAML,并且您可以指定要附加数据的路径。


推荐阅读