Java 在YAML嵌套数据中搜索值
我目前正试图将YAML文件解析为运行某些测试的输入/配置。问题是:使用Jackson,嵌套数据似乎不适合类,无论我为其设计了什么结构,几乎每次我都会得到这样的结果:Java 在YAML嵌套数据中搜索值,java,xpath,jackson,yaml,snakeyaml,Java,Xpath,Jackson,Yaml,Snakeyaml,我目前正试图将YAML文件解析为运行某些测试的输入/配置。问题是:使用Jackson,嵌套数据似乎不适合类,无论我为其设计了什么结构,几乎每次我都会得到这样的结果: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token 我打算使用类似XPath的方法简单地搜索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;
}
}
}
其思想是为YAMLInput类构建一个构造函数:
与这个假设的SearchableYAMLData类最接近的可用工具是什么?您得到的错误可能是由于您显示的YAML与您显示的类不对应。YAML数据中的someObjList是一个包含键值对的映射,第一个键是obj1,而在类中,它是一个ArrayList。这对应于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"));
根节点可以是ScalarNode、MappingNode或SequenceNode。后两个节点将包含您可以访问的子节点。这种结构对于类似XPath的搜索当然是可行的
如果您追求性能,一种更快的方法是使用SnakeYaml的顺序解析接口。基本上,您可以从解析器中连续查询下一个事件,并检查您正在搜索的路径是否包含它。如果是这样,请继续查询其子元素并在其中的路径中搜索下一个元素。如果没有,则解析并转储当前事件的所有子内容,然后继续搜索当前路径元素
如果您可以阅读Python,您可以从中获得一些灵感,通过事件解析输入YAML,并可以指定要附加数据的路径。您得到的错误可能源于您显示的YAML与您显示的类不对应。YAML数据中的someObjList是一个包含键值对的映射,第一个键是obj1,而在类中,它是一个ArrayList。这对应于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"));
根节点可以是ScalarNode、MappingNode或SequenceNode。后两个节点将包含您可以访问的子节点。这种结构对于类似XPath的搜索当然是可行的
如果您追求性能,一种更快的方法是使用SnakeYaml的顺序解析接口。基本上,您可以从解析器中连续查询下一个事件,并检查您正在搜索的路径是否包含它。如果是这样,请继续查询其子元素并在其中的路径中搜索下一个元素。如果没有,则解析并转储当前事件的所有子内容,然后继续搜索当前路径元素
如果您可以阅读Python,您可以从中获得一些灵感,通过事件解析输入YAML,并可以指定要附加数据的路径。您可以看到,无法反序列化java.util.ArrayList的实例,因为您在根级别定义了ArrayList容器,但YAML文件包含对象。为了避免这种情况,我们需要将ObjectMapper配置为接受单个对象(如数组):
此外,模型中未定义obj1和obj2。因此,您应该删除它们或创建额外的包装器对象。但如果只需要遍历YAML文件,则可以将其作为映射读取。以下代码:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.File;
import java.util.Map;
public class YamlApp {
public static void main(String[] args) throws Exception {
File yamlFile = new File("./resource/test.yaml").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
Map yaml = mapper.readValue(yamlFile, Map.class);
System.out.println(yaml);
}
}
印刷品:
{container={name=Cont1, path=/storage/outputFolder, intList=[100, 200, 300], strList=[strFirst, strSecond, strThird], someObjList={obj1={objName=strname, strList=[100, 200, 300]}, obj2={objName=strname2, strList=[1002, 2002, 3002]}}}}
您可以看到,无法从START_对象标记反序列化java.util.ArrayList的实例,因为在根级别您定义了ArrayList容器,但YAML文件包含对象。为了避免这种情况,我们需要将ObjectMapper配置为接受单个对象(如数组):
此外,模型中未定义obj1和obj2。因此,您应该删除它们或创建额外的包装器对象。但如果只需要遍历YAML文件,则可以将其作为映射读取。以下代码:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.File;
import java.util.Map;
public class YamlApp {
public static void main(String[] args) throws Exception {
File yamlFile = new File("./resource/test.yaml").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
Map yaml = mapper.readValue(yamlFile, Map.class);
System.out.println(yaml);
}
}
印刷品:
{container={name=Cont1, path=/storage/outputFolder, intList=[100, 200, 300], strList=[strFirst, strSecond, strThird], someObjList={obj1={objName=strname, strList=[100, 200, 300]}, obj2={objName=strname2, strList=[1002, 2002, 3002]}}}}