微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java - SnakeYaml |获取文件的所有键

如何解决Java - SnakeYaml |获取文件的所有键

首先,我一直在阅读一些关于密钥的帖子,但没有人问我如何获取 yaml 文件的所有密钥的问题,只询问如何获取特定密钥。

现在,我想创建一个文件更新程序,它可以工作,但它只更新第一个键,没有“子键”,代码如下:

InputStream resource = getClass().getClassLoader().getResourceAsstream(dir);
Map<String,Object> data = new Yaml().load(resource);
for(String str : data.keySet()) {
    DBot.getConsole().log(str);
    if(!contains(str)) {
        set(str,data.get(str));
    }
}

文件如下所示:

Features.Example.StringA

Features.Example.StringB

点是空格使它们成为子键(堆栈溢出将它们放在一行上,抱歉)

现在的问题是,更新程序只有在删除“Features”时才会工作,而且调试只会打印“Features”,这意味着只有第一个键在键集中,我怎样才能获得所有键?

解决方法

SnakeYAML 正在将 yaml 解码为递归数据结构。例如:

public static void main(String[] args) {
    String yaml = "a:\n  b: \n    c: \"string\"";
    Map<String,Object> data = new Yaml().load(yaml);
    System.out.println(data);
}

打印出来:

{a={b={c=string}}}

哪个是 Map<String,Map<String,String>>>

为了展示如何以递归方式使用它,以下是打印出一些细节的方法。

private static void printMapRecursive(final Map<?,?> data) {
        for(Object key : data.keySet()) {
            System.out.println("key " + key + " is type " + key.getClass().getSimpleName());
            final Object value = data.get(key);
            if(value instanceof Map){
                System.out.println("value for " + key + " is a Map - recursing");
                printMapRecursive((Map<?,?>) value);
            } else {
                System.out.println("value " + value + " for " + key + " is type " + value.getClass());
            }
        }
    }

您可以使用 printMapRecursive(data); 调用并查看输出:

key a is type String
value for a is a Map - recursing
key b is type String
value for b is a Map - recursing
key c is type String
value string for c is type class java.lang.String

以及递归转换键的示例:

private static Map<?,?> mutateMapRecursive(final Map<?,?> data,Function<String,String> keyFunction) {
        Map<Object,Object> result = new HashMap<>();
        for (Object key : data.keySet()) {
            final Object value = data.get(key);
            if(key instanceof String){
                key = keyFunction.apply((String) key);
            }
            if (value instanceof Map) {
                result.put(key,mutateMapRecursive((Map<?,?>) value,keyFunction));
            }
            else {
                result.put(key,value);
            }
        }
        return result;
    }

称为:

final Map<?,?> transformed = mutateMapRecursive(data,(key) -> "prefix_" + key);
System.out.println(transformed);

发射:

{prefix_a={prefix_b={prefix_c=string}}}

,

我终于找到了如何返回每个键以“.”分隔的 Set,Bukkit/Spigot 开发人员可能对此很熟悉。首先,你必须创建一个这样的类:

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class YamlKeys {

    private static Set<String> keys = new HashSet<String>();
    private static String path = "";

    YamlKeys(Map<?,?> data) {
        getKeysRecursive(data);
    }

    private void getKeysRecursive(final Map<?,?> data) {
        for(Object key : data.keySet()) {
            final Object value = data.get(key);
            if(key instanceof String) {
                if(path.length() == 0) {
                    path = (String)key; // If the key is the first on the path,don't include separator.
                } else {
                    path = path+"."+(String)key; // Here is the separator,you can change it.
                }
            }
            if(value instanceof Map) {
                getKeysRecursive((Map<?,?>) value); // A value map has been found,recursing with that value.
            } else {
                keys.add(path); // No more maps have been found,we can add the path and stop recursing.
                if(path.contains(".")) {
                    path = path.substring(0,path.lastIndexOf(".")); // Removing last key,so if a value contains more than one key,it won't appear again.
                }
            }
        }
        path = ""; // This is important,reset the path.
    }

    Set<String> getKeys() {
        return keys;
    }
}

然后,要调用它并选择是要获取深度键还是“普通”键,您可以创建这样的方法:

public Set<String> getKeys(boolean deep) {
    Map<String,Object> data = new Yaml().load(inStream);
    if(!deep) {
        return data.keySet();
    } else {
        return new YamlKeys(data).getKeys();
    }
}

为了测试它,我们可以使用以下代码:

new YamlKeys(data).getKeys().stream().forEach(key -> System.out.println(key));

使用这个文件:

FirstKey:
  SecondKey:
    Enabled: true
    Text: "Some text"
    AnotherKey:
      AValue: true
AnotherTest:
  Enabled: false
Value: true

它返回这个输出:

FirstKey.SecondKey.AnotherKey.AValue
FirstKey.SecondKey.Enabled
FirstKey.SecondKey.Text
Value
AnotherTest.Enabled

感谢 roby 告诉我递归。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。