如何解决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 举报,一经查实,本站将立刻删除。