我正在研究将YAML用于某种复杂的元数据语言.如果我们可以使用YAML的锚点和引用,这将有助于使文档更小,更简单.我写了一些测试代码,似乎表明Jackson的YAML实现不支持这个功能(和/或没有表现出SnakeYAML对此功能的支持).
这是我的测试YAML文件:
set_one:
bass: tama rockstar 22x16
snare: &ludwig ludwig supralight 6.5x15
tom1: tama rockstar 12x11
tom2: tama rockstar 16x16
set_two:
snare: *ludwig
Run Code Online (Sandbox Code Playgroud)
我正在解析这个文件:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
JsonNode nodeTree = mapper.readTree(fis);
examineObject(nodeTree, 0);
}
...
Run Code Online (Sandbox Code Playgroud)
这是我的"examineObject()"方法(你可能猜到它的作用):
key = "set_one", type = OBJECT
key = "bass", type = STRING, value = "tama rockstar 22x16"
key = "snare", type = STRING, value = "ludwig supralight 6.5x15"
key = "tom1", type = STRING, value = "tama rockstar 12x11"
key = "tom2", type = STRING, value = "tama rockstar 16x16"
key = "set_two", type = OBJECT
key = "snare", type = STRING, value = "ludwig"
Run Code Online (Sandbox Code Playgroud)
很明显,有些东西可以省略"set_one.snare"中的锚值,但是在调试器中,我无法在JsonNode中的任何位置找到该元素的值.真正的问题是"set_two.snare"的价值只是"路德维希".参考符号('*')已被剥离,但该值是引用的值,而不是它所引用的元素.
我正在使用Jackson版本2.8.3和SnakeYaml版本1.17.我被限制使用杰克逊,因为这只是一个已经使用杰克逊用于JSON的更大项目的一部分.
我真正想要的是杰克逊能否自动解析引用并复制引用的值.在我的例子中,这意味着"set_two.snare"的值将是"ludwig supralight 6.5x15".
如果我不能得到我的第一选择,那么我希望杰克逊保留锚点和引用,以便我可以手动后处理节点树并自己解析引用.例如,当我看到"set_two.snare"的值为"*ludwig"时,我可以在树中搜索锚点为"&ludwig"的节点,并制作该节点的副本.
如果有答案,我觉得它可能会以某种方式涉及"com.fasterxml.jackson.dataformat.yaml.YAMLParser.Feature"类.遗憾的是,我找不到任何有关这些功能的文档(如果存在),这些功能将启用我正在寻找的行为.
首先,Jackson 实际上确实支持 YAML 锚点和引用,至少在某种程度上,它们与 Jackson 支持 Object Id 引用的方式配合使用@JsonIdentityInfo:限制是您不能(例如)引用 am Object 的一个键/值对。
但身份 id/引用处理仅适用于通过使用 注释指定的类型和属性@JsonIdentityInfo。因此,您必须注释可能引用的类型或属性(不需要两者都做)。
这里可能有帮助的一件事是考虑 Jackson 处理的对象 Id 对于所有格式都非常相似:因此,尽管jackson-dataformat-yaml确实公开了 YAML 具有(而 JSON 没有)的“本机”对象(和类型)ID,但在数据绑定级别进行处理是相同的。因此,如果您可以使对象 ID/引用与 JSON 一起使用(这会添加额外的 id 属性),那么它也将与 YAML 一起使用。
还有一件相关的额外事情:YAMLParser.Feature.USE_NATIVE_OBJECT_ID它决定了在编写 YAML 时如何表达引用和 id —— 默认情况下,它使用本机锚点,但可以将其关闭以使用“类似 JSON”的普通属性。
我希望这有帮助。要获得更多帮助,最好的地方是jackson-users邮件列表。
小智 5
由于 Jackson YAML 不支持锚点和引用(问题),因此最好回退到 SnakeYaml 来解析 YAML 文件,然后将其转换为 Jackson 的格式,以利用 Jackson 的灵活性。Snake Yaml 支持锚点,与 Jackson 不同(尽管 Jackson 在后台使用 Snakeyaml 来解析 Yaml 文件)。
import java.io.{File, FileInputStream, FileReader}
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
import org.yaml.snakeyaml.Yaml
// Parsing the YAML file with SnakeYAML - since Jackson Parser does not support Anchors and references
val ios = new FileInputStream(new File(yamlFilePath))
val yaml = new Yaml()
val mapper = new ObjectMapper().registerModules(DefaultScalaModule)
val yamlObj = yaml.loadAs(ios, classOf[Any])
// Converting the YAML to Jackson YAML - since it has more flexibility
val jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(yamlObj) // Formats YAML to a pretty printed JSON string - easy to read
val jsonObj = mapper.readTree(jsonString)
Run Code Online (Sandbox Code Playgroud)
生成的 jsonObj 是一个 JsonNode,它是 Jackson 中的核心数据格式之一。我们可以使用 as & get 方法轻松遍历 YAML 文件:
jsonObj.at("/parent/first_level_child/second_level_child")
jsonObj.get("key")
Run Code Online (Sandbox Code Playgroud)
由于 YAML 格式非常接近 JSON 格式,因此在大多数情况下不应丢失数据。此外,Jackson 的 JsonNode 格式允许我们使用 Jackson-Json 解析器的额外灵活性——这是 Jackson-YAML 解析器所缺少的。
| 归档时间: |
|
| 查看次数: |
1801 次 |
| 最近记录: |