当前位置: 首页 > 知识库问答 >
问题:

SnakeYaml,读入类中特定标记下的所有内容,忽略其他所有内容

牛枫
2023-03-14

我有一些YAML文件包含很多配置,但我只需要其中的一个标记(mytag)。

component:
  field1:
    - name: nnn1
  field2:
    - name: mmm1

mytag:
   description: hello
   mycomponents:
      - propertyA: aaa
        propertyB: bbb

theirtag:
   bbb: 111
   comps:
      - propA: aaa
        prop: bbb

我需要加载:

class MyClass {
   String description;
   List<MyComponent> mycomponents:
}

如何使用SnakeYaml做到这一点?我没能很快找到任何有用的例子。

跟进:如果我的标签嵌套得更深,该怎么办:(boo/mytag)

boo:
  mytag:
    description: hello
    mycomponents:
      - propertyA: aaa
        propertyB: bbb

谢谢

共有1个答案

赫连瀚
2023-03-14

这不是小事。虽然使用自定义构造函数可能是可行的,但对于这种情况,它们的接口很难处理,我不确定如何处理。

相反,您可以覆盖默认的解析器行为,只需丢弃mytag键周围的任何事件,这样解析器发出的事件流只包含mytag键值内的事件。下面是一个简单的工作示例:

package droggeljug;

import org.yaml.snakeyaml.parser.ParserImpl;
import org.yaml.snakeyaml.events.*;
import org.yaml.snakeyaml.composer.Composer;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.reader.StreamReader;

import java.io.*;
import java.util.List;

public class Main {

    public static class MyParser extends ParserImpl {
        private final String containingKey;

        private int depth = -1;
        private boolean checked = false;

        public MyParser(StreamReader reader, boolean emitComments, String containingKey) {
            super(reader, emitComments);
            this.containingKey = containingKey;
        }

        @Override
        public Event peekEvent() {
            if (checked) return super.peekEvent();
            Event e;
            while (true) {
                boolean seenContainingKey = false;
                e = super.peekEvent();
                switch (e.getEventId()) {
                    case StreamStart:
                    case DocumentStart:
                    case Comment:
                    case StreamEnd:
                    case DocumentEnd:
                        return e;
                    case Scalar:
                        if (depth == -1) {
                            if (containingKey.equals(((ScalarEvent)e).getValue())) {
                                seenContainingKey = true;
                                break;
                            }
                        }
                    case Alias:
                        break;
                    case MappingStart:
                    case SequenceStart:
                        if (depth > -1) {
                            depth++;
                        }
                        break;
                    case MappingEnd:
                    case SequenceEnd:
                        if (depth > -1) {
                            depth--;
                        }
                        break;
                }
                if (seenContainingKey) {
                    depth = 0;
                } else if (depth > -1) break;
                checked = true; super.getEvent(); checked = false; // discard
            }

            if (depth == 0) depth = -1;
            checked = true;
            return e;
        }

        public Event getEvent() {
            Event ret = super.getEvent();
            checked = false;
            return ret;
        }
    }

    public static class MyYaml extends Yaml {
        private Object loadContainedFromReader(StreamReader sreader, Class<?> type, String containingKey) {
            Composer composer = new Composer(new MyParser(sreader,
                    loadingConfig.isProcessComments(), containingKey), resolver, loadingConfig);
            constructor.setComposer(composer);
            return constructor.getSingleData(type);
        }

        @SuppressWarnings("unchecked")
        public <T> T loadContainedAs(Reader io, Class<T> type, String containingKey) {
            return (T) loadContainedFromReader(new StreamReader(io), type, containingKey);
        }
    }

    public static class MyClass {
        public static class MyComponent {
            public String propertyA, propertyB;
        }

        public String description;
        public List<MyComponent> mycomponents;
    }

    private static final String input =
            "component:\n" +
            "field1:\n" +
            "  - name: nnn1\n" +
            "field2:\n" +
            "  - name: mmm1\n" +
            "mytag:\n" +
            "    description: hello\n" +
            "    mycomponents:\n" +
            "      - propertyA: aaa\n" +
            "        propertyB: bbb\n" +
            "theirtag:\n" +
            "    bbb: 111\n" +
            "    comps:\n" +
            "      - propA: aaa\n" +
            "        prop: bbb\n";

    public static void main(String args[]) {
        MyYaml yaml = new MyYaml();
        MyClass data = yaml.loadContainedAs(new StringReader(input), MyClass.class, "mytag");
        System.out.println("description = " + data.description);
        for (MyClass.MyComponent c : data.mycomponents) {
            System.out.println("component: (" + c.propertyA + ", " + c.propertyB + ")");
        }
    }
}

过滤代码不完全正确,例如,如果mytag是某个值或序列项,则会失败。您需要跟踪解析器状态,以确保当前标量是映射键。我没有实现它,因为代码已经足够长了。

 类似资料:
  • 我试图创建一个随机数生成器程序,跟踪玩家的胜利,损失,获胜百分比和总奖金。该程序的逻辑是,玩家每节获得3次机会,计算机生成一个随机数,玩家需要猜测或者更确切地说应该匹配。 我试过用如果 如果您对此有任何意见,我们将不胜感激。 游戏类别:

  • 有时,项目中的许多广为流传的惯例和协定变得非常重要,你需要记录下来。为了保证这种文档的正统性,要清楚的表明这些内容基于邮件列表的讨论,并已经形成协定开始生效。随着你的编写,应当引用邮件列表归档中的相关讨论,对于任何不能确定的要点,要重新询问并确认。文档中不应当包含任何出其不意的东西:它不应当是协议的来源,而只是对于协议的描述。当然,如果它足够成功,人们会开始引用它来作为自己权利的来源,但是这只是说

  • 我想把一个字符串拆分成单个单词。如果字符串是: 我想存储为: 如果我使用则变成。我该怎么做呢

  • 我使用php删除文件夹包含删除的帖子的图像。我正在使用下面的代码,我在网上找到的,做得很好。 我想知道当文件夹中有其他文件夹时,如何仅删除文件夹中的特定文件夹。 当我使用下面的代码时,如何做到这一点?使用:/dev/images/norman/8-

  • 问题内容: 我想知道是否有任何方法可以导入包的全部内容,从而不必在调用包名称之前对包中的内容添加前缀? 例如,有一种方法可以替代此方法: 有了这个: 问题答案: Go编程语言规范 进口报关单 如果出现一个明显的句点(。)而不是名称,则在该软件包的package块中声明的所有软件包导出标识符都将在导入源文件的file块中声明,并且必须在不使用限定符的情况下进行访问。 例如, 游乐场:https :

  • 我对log4j2比较陌生。当前,我有以下配置文件: 如果我通过静态记录器在这两个类Consoleain和ClientMain中记录一些东西 而且 他们总是使用根记录器的附加器和级别。如果根记录器的级别是“错误”,那么它永远不会显示任何调试级别的日志输出,即使单个记录器的级别是调试。而且,它总是追加到根记录器中指定的日志文件,而不是类的记录器中指定的日志文件。 所以,根记录器似乎以某种方式覆盖了所有