如何使用 Java 库将标记的 YAML 对象转换为 JSON 对象?

Posted

技术标签:

【中文标题】如何使用 Java 库将标记的 YAML 对象转换为 JSON 对象?【英文标题】:How do you convert tagged YAML objects to JSON objects using a Java library? 【发布时间】:2021-12-16 01:07:53 【问题描述】:

如何解析包含标记映射的 YAML 文件并返回嵌套的 Java Map 对象,其中每个 Java Map 包含来自相应 YAML 映射的所有条目,以及键为字符串“objectType”的条目” 并且值是标签的(字符串)名称?

换句话说,我想解析标记的 YAML 对象,就好像它们是带有类型条目的 JSON 对象一样。

例如,你如何解析这个:

!ControlGroup
name: myGroup
controls:
- !Button
  name: button1
  size: 10
- !Knob
  name: knob1
  maxValue: 11
  size: 7

好像是这样的?:

objectType: ControlGroup
name: myGroup
controls:
- objectType: Button
  name: button1
  size: 10
- objectType: Knob
  name: knob1
  maxValue: 11
  size: 7

我已经在我正在处理的项目中使用 SnakeYAML,所以如果存在使用 SnakeYAML 的解决方案,那将是理想的。

【问题讨论】:

我猜你可以注入一个自定义解析器,将标签处理为objectType: Button 对,但遗憾的是,SnakeYAML 存储库由于某种原因变得私有,所以我无法检查细节。如果缩进实际上并没有像您显示的代码那样被破坏,那么快速的正则表达式替换输入可能是简单的解决方案。 【参考方案1】:

我以单元测试的形式编写了code,它准确地解析了您使用snakeYml 提供的文件。运行它。

 @Test
    void testYamlConvert() throws IOException 

        // Step 1: Raad in file
        var in = this.getClass().getResourceAsStream("/test.yml");
        // System.out.println(in);
        String yml = IOUtils.toString(in,"UTF-8");


        // Step 2: Do in memory replacement to standard form
        Pattern p = Pattern.compile("!!(.*)");
        Matcher m = p.matcher(yml);

        String ymlWithReplacement = yml;
        while (m.find()) 
            var nameToken = m.group().substring(2);
            // System.out.println("Name token:"+nameToken);
            ymlWithReplacement=ymlWithReplacement.replace("!!"+nameToken, "objectType: "+nameToken);
        
        // System.out.println(ymlWithReplacement);

        // Step 3: Do the parse ...
        Yaml yaml = new Yaml();
        var myYamlMap = (Map<String,Object>) yaml.load(ymlWithReplacement);

        for(var entry : myYamlMap.entrySet()) 
            System.out.println("Key:" + entry.getKey() + "Value:" + entry.getValue());
        
    

生成的地图如下所示。

从这里获取必要的数据应该很容易。 cmets中解释了工作原理。

如果您需要其他东西让我能够领取赏金,请告诉我!

【讨论】:

解决方案应该内联添加。 10 年后,链接可能会消失,并且无法访问解决方案,即使问题可能仍然相关 好的。会做。谢谢。 @user10264746 这个解决方案对你有用吗?【参考方案2】:

这是有效的,

!!ControlGroup
name: myGroup
controls:
  - !!Button
    name: button1
    size: 10
  - !!Knob
    name: knob1
    maxValue: 11
    size: 7

Yaml yaml = new Yaml();
        InputStream url = SnakeYml.class.getClassLoader().getResourceAsStream("sample.yaml");
        Map<String, Object> obj = yaml.load(url);
        System.out.println(obj);
public class ControlGroup 
    String name;
    public ControlGroup() ;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

....

【讨论】:

不幸的是,这并没有解决问题,因为它没有将条目“objectType:ControlGroup”插入到生成的地图中。【参考方案3】:

试试这个,

        ControlGroup controlGroup = yaml.load(url);
        controlGroup.setObjectType(ControlGroup.class.getName());
        System.out.println(yaml.dumpAsMap(controlGroup));

public class ControlGroup 
    String objectType = this.getClass().getTypeName();
    String name;
    public ControlGroup() ;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    
    public String getObjectType()
    
        return this.getClass().getTypeName();
    
    public void setObjectType(String className)
    
        this.objectType = className;
    



MAP --> 
name: myGroup
objectType: ControlGroup

【讨论】:

我很欣赏这篇文章,但它实际上并没有解决问题,因为它没有为“旋钮”和“按钮”创建地图条目。更重要的是,我正在寻找一种不涉及向每个 YAML 实例化类添加两种方法的解决方案。

以上是关于如何使用 Java 库将标记的 YAML 对象转换为 JSON 对象?的主要内容,如果未能解决你的问题,请参考以下文章