在 YAML 嵌套数据中搜索值
Search for value within YAML nested data
我目前正在尝试将 YAML 文件解析为 input/configuration 以用于 运行 一些测试。问题是:使用 Jackson,无论我为它设计的结构如何,嵌套数据似乎都不适合 class,几乎每次我得到这样的东西时:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
我打算使用类似的 XPath 方法简单地 "search" 用于 YAML 文件中的数据,而不用担心映射对象和有限的嵌套级别。
示例如下 class:
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
class 构建构造函数:
public YAMLInput( SearchableYAMLData data) {
for(SearchableYAMLData container : data.getList("container")){
this.containers.add( new SomeContainer());
this.containers.get(0) = container.get("name");
//...
}
}
最接近这个假设的可用工具是什么 SearchableYAMLData
class?
您得到的错误可能源于您显示的 YAML 与您显示的 class 不对应。 YAML 数据中的 someObjList
是一个映射(包含 key-value 对,第一个键是 obj1
),而在你的 class 中,它是一个 ArrayList<SomeObject>
。这对应于 YAML 数据中的一个序列,应该如下所示:
someObjList:
- objName: strname
strList:
- 100
- 200
- 300
- # (...)
但是,我不确定,因为您并没有真正显示产生错误的代码。
也就是说,如果您正在寻找一种通过任意 YAML 进行搜索的方法,请不要使用 Jackson。 Jackson 是一个用于(反)序列化的工具,您不想反序列化您的 YAML;你只想走它的结构。为此,您可以使用 Jackson 使用的 YAML 解析器 SnakeYAML:
Yaml yaml = new Yaml();
Node root = yaml.compose(new StringReader("foo: bar"));
root
将是 ScalarNode
、MappingNode
或 SequenceNode
。后两个将包含 child 个可以下降的节点。这种结构对于XPath-like seaching当然是可行的
如果您追求性能,更快的方法是使用 SnakeYaml 的顺序 parse
接口。基本上,您不断地从解析器查询下一个事件,并检查您正在搜索的路径是否包含它。如果是,继续查询它的 children 并在那里搜索路径中的下一个元素。如果不是,则解析并转储当前事件的所有 child 内容,然后继续搜索当前路径元素。
如果你能阅读 Python,你可以从 中获得一些灵感,它通过事件解析输入 YAML,你可以指定要附加数据的路径。
您看到 Cannot deserialize instance of "java.util.ArrayList" out of START_OBJECT token
,因为您在根级别定义了 ArrayList<SomeContainer> containers
,但 YAML
文件包含 object
。为避免这种情况,我们需要配置 ObjectMapper
以接受单个对象,例如 array
:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
此外,obj1
和 obj2
未在您的模型中定义。所以你应该删除它们或创建额外的包装器对象。但是如果你只需要遍历 YAML
个文件,你可以把它读成 Map
。下面的代码:
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]}}}}
我目前正在尝试将 YAML 文件解析为 input/configuration 以用于 运行 一些测试。问题是:使用 Jackson,无论我为它设计的结构如何,嵌套数据似乎都不适合 class,几乎每次我得到这样的东西时:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
我打算使用类似的 XPath 方法简单地 "search" 用于 YAML 文件中的数据,而不用担心映射对象和有限的嵌套级别。
示例如下 class:
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
class 构建构造函数:
public YAMLInput( SearchableYAMLData data) {
for(SearchableYAMLData container : data.getList("container")){
this.containers.add( new SomeContainer());
this.containers.get(0) = container.get("name");
//...
}
}
最接近这个假设的可用工具是什么 SearchableYAMLData
class?
您得到的错误可能源于您显示的 YAML 与您显示的 class 不对应。 YAML 数据中的 someObjList
是一个映射(包含 key-value 对,第一个键是 obj1
),而在你的 class 中,它是一个 ArrayList<SomeObject>
。这对应于 YAML 数据中的一个序列,应该如下所示:
someObjList:
- objName: strname
strList:
- 100
- 200
- 300
- # (...)
但是,我不确定,因为您并没有真正显示产生错误的代码。
也就是说,如果您正在寻找一种通过任意 YAML 进行搜索的方法,请不要使用 Jackson。 Jackson 是一个用于(反)序列化的工具,您不想反序列化您的 YAML;你只想走它的结构。为此,您可以使用 Jackson 使用的 YAML 解析器 SnakeYAML:
Yaml yaml = new Yaml();
Node root = yaml.compose(new StringReader("foo: bar"));
root
将是 ScalarNode
、MappingNode
或 SequenceNode
。后两个将包含 child 个可以下降的节点。这种结构对于XPath-like seaching当然是可行的
如果您追求性能,更快的方法是使用 SnakeYaml 的顺序 parse
接口。基本上,您不断地从解析器查询下一个事件,并检查您正在搜索的路径是否包含它。如果是,继续查询它的 children 并在那里搜索路径中的下一个元素。如果不是,则解析并转储当前事件的所有 child 内容,然后继续搜索当前路径元素。
如果你能阅读 Python,你可以从
您看到 Cannot deserialize instance of "java.util.ArrayList" out of START_OBJECT token
,因为您在根级别定义了 ArrayList<SomeContainer> containers
,但 YAML
文件包含 object
。为避免这种情况,我们需要配置 ObjectMapper
以接受单个对象,例如 array
:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
此外,obj1
和 obj2
未在您的模型中定义。所以你应该删除它们或创建额外的包装器对象。但是如果你只需要遍历 YAML
个文件,你可以把它读成 Map
。下面的代码:
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]}}}}