我正在研究将YAML用于某种复杂的元数据语言。如果我们可以使用YAML's anchors and references,这将有助于使文档更小,更简单。我写了一些测试代码,似乎表明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
我正在解析这个文件:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
JsonNode nodeTree = mapper.readTree(fis);
examineObject(nodeTree, 0);
}
...
这是我的" 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"
显然有些东西足以省略来自" set_one.snare"的锚值。但是,在调试器中,我无法在JsonNode中的任何位置找到该元素的值。真正的问题是" set_two.snare"只是"路德维希"。参考符号(' *')已被剥离,但该值是引用的值,而不是它所引用的元素。
我使用Jackson版本2.8.3和SnakeYaml版本1.17。我被限制使用杰克逊,因为这只是一个更大的项目的一部分,该项目已经使用杰克逊作为JSON。
我真正想要的是杰克逊能否自动解析引用并复制引用的值。在我的例子中,这意味着" set_two.snare"将是"路德维希超级6.5x15"。
如果我无法获得我的第一选择,那么我希望Jackson保留锚点和引用,以便我可以手动后处理节点树并自行解析引用。例如,当我看到" set_two.snare"的值时是" * ludwig",我可以在树上搜索一个锚点为"& ludwig"并制作该节点的副本。
如果有答案,我觉得它可能涉及" com.fasterxml.jackson.dataformat.yaml.YAMLParser.Feature"不知怎的。遗憾的是,我无法找到有关这些功能的文档(如果存在),这些文档将启用我正在寻找的行为。
答案 0 :(得分:1)
我只是想让Jackson的锚/别名工作...而失败了。 您可以看到here未实现基于别名的ID支持。 _currentAnchor实例变量是由getObjectId()设置和公开的,但是我没有找到一种实用的方法来挂接到Jackson以使用该方法。这不是我第一次使用Jacksons Object-Id解析体系结构。建议不要花太多时间。
我的解决方案是直接使用snakeyaml库。
答案 1 :(得分:0)
首先,杰克逊确实支持YAML锚点和引用,至少在程度上它们与杰克逊如何使用@JsonIdentityInfo
支持对象ID引用有关:限制是你不能 - 例如 - 引用一个键/ value对am am。
但是,身份标识/引用处理仅对通过使用@JsonIdentityInfo
进行批注指定的类型和属性启用。
因此,您必须注释可能被引用的类型或属性(不需要同时执行这两种操作)。
这里可能有用的一件事是考虑到Jackson的Object Id处理对于所有格式非常相似:所以尽管jackson-dataformat-yaml
确实暴露了#34; native" YAML具有的对象(和类型)ID(和JSON没有),在数据绑定级别的处理是相同的。因此,如果您可以使用JSON(添加额外的id属性)使对象ID /引用工作,它也将与YAML一起使用。
还有一件事是相关的:YAMLParser.Feature.USE_NATIVE_OBJECT_ID
确定在编写YAML时如何表达引用和id - 默认情况下,它使用本机锚点,但可以关闭它以使用"类JSON"平原属性。
我希望这会有所帮助。如需其他帮助,最好的地方是jackson-users
邮件列表。
答案 2 :(得分:0)
由于Jackson YAML不支持锚和引用(issue),因此最好退回SnakeYaml来解析YAML文件,然后将其转换为Jackson格式,以利用Jackson灵活性的优势。与杰克逊不同,Snake Yaml支持锚点(尽管杰克逊在后台使用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)
生成的jsonObj是一个JsonNode,它是Jackson的核心数据格式之一。我们可以使用as&get方法轻松遍历YAML文件:
jsonObj.at("/parent/first_level_child/second_level_child")
jsonObj.get("key")
由于YAML格式非常接近JSON格式,因此在大多数情况下不应丢失数据。此外,Jackson的JsonNode格式使我们能够使用Jackson-Json解析器的其他灵活性-Jackson-YAML解析器中缺少的。