Closed ghost closed 2 years ago
Because without quotes that would be a number not a string.
Because without quotes that would be a number not a string.
java.lang.String user.getId() the discord ID of the User
It returns a string, though? And even when doing String.valueOf(user.getID());
it still adds single quotes
I mean, in yaml, if strings with only numbers are not quoted, it'll be parsed as a number. So it needs to be quoted to remain as a string. Therefore the numbers themselves are the special characters.
I mean, in yaml, if strings with only numbers are not quoted, it'll be parsed as a number. So it needs to be quoted remain as a string.
After changing it around a little, it does seem you're right. My apologies, seems that is the case. But with that, I'm getting a new issue: getKeys is returning null when attempting to get all of the keys under users
if i'm not wrong, keys can't be number, only string.
if i'm not wrong, keys can't be number, only string.
I added characters to the key to make it a string
users: 192230467519512576A: xp: 0
Code that I'm using to loop over the file
` ConfigurationSection users = userYaml.getConfigurationSection("users");
Set<String> values = users.getKeys(false);
for (String value : values) {
System.out.println(users.getInt(value + ".xp"));
}`
As stated, keys are yaml strings by default, so numbers are wrapped using single quotes in keys.
For values you can specify the quote style with set(String, Object, QuoteStyle)
(#50) but not for keys. Maybe you could dump those keys with plain style using a custom snakeyaml representer using setImplementation
, but probably is overcomplicating things for your use case.
For your second problem, what do you mean getKeys
returns null? It cannot return null, at least it will be an empty set.
The getConfigurationSection
returns null if the path is not present in the file.
You can check for null to see if the section exists, or use the isConfigurationSection
method and create a new section with createSection
if it does not exist. If you are unsure if the users section exist or want to create it inside your code (instead of providing it as a resource) you could do something like this:
YamlFile userYaml = new YamlFile("users.yml");
// Create a new file if not exists, otherwise load its contents
userYaml.createOrLoad();
// Get users section if already created
ConfigurationSection users = userYaml.getConfigurationSection("users");
if (users == null) {
// Create the section if it does not exist
users = userYaml.createSection("users");
}
// Adding a new user
String newUserId = "192230467519512576";
users.set(newUserId + ".xp", 100);
// Reading users
Set<String> userIds = users.getKeys(false);
for (String userId : userIds) {
int xp = users.getInt(userId + ".xp");
System.out.println(userId + ": " + xp + " XP");
}
// Save changes
userYaml.save();
I've excluded exception handling.
Output
192230467519512576: 100 XP
users.yml
users:
'192230467519512576':
xp: 100
If your file only has users then you could avoid the users
key entirely, but that's a personal preference.
I suggest you to have a look at the serialization example with the Person
class to see an example of yaml serialization using java objects if you have created a User
class to wrap the xp and other attributes, allowing you to directly save and retrieve the User
objects to your yaml file.
As a reference for your first question, if needed, this is how you would set a custom representer to dump string integers without quotes in keys.
First, create the custom representer:
CustomKeyRepresenter.java
import org.simpleyaml.configuration.implementation.snakeyaml.SnakeYamlRepresenter;
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
import org.simpleyaml.configuration.implementation.snakeyaml.lib.nodes.*;
import org.simpleyaml.configuration.implementation.snakeyaml.lib.resolver.Resolver;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CustomKeyRepresenter extends SnakeYamlRepresenter {
private boolean isKey = false;
public CustomKeyRepresenter(DumperOptions dumperOptions) {
super(dumperOptions);
}
@Override
protected Node representMapping(Tag tag, Map<?, ?> mapping, DumperOptions.FlowStyle flowStyle) {
List<NodeTuple> value = new ArrayList<>(mapping.size());
MappingNode node = new MappingNode(tag, value, flowStyle);
this.representedObjects.put(this.objectToRepresent, node);
for (Map.Entry<?, ?> entry : mapping.entrySet()) {
this.isKey = true;
Node nodeKey = this.representData(entry.getKey());
this.isKey = false;
Node nodeValue = this.representData(entry.getValue());
value.add(new NodeTuple(nodeKey, nodeValue));
}
node.setFlowStyle(this.defaultFlowStyle);
return node;
}
@Override
protected Node representScalar(Tag tag, String value, DumperOptions.ScalarStyle style) {
if (style == null) {
style = this.defaultScalarStyle;
}
if (this.isKey && tag == Tag.STR && style == DumperOptions.ScalarStyle.PLAIN && isInt(value)) {
tag = Tag.INT;
}
return new ScalarNode(tag, value, null, null, style);
}
private static boolean isInt(final String s) {
return s != null && Resolver.INT.matcher(s).matches();
}
}
Then, create the YamlFile with your custom representer:
// Create a YamlFile with a custom representer
SnakeYamlRepresenter customRepresenter = new CustomKeyRepresenter(new DumperOptions());
YamlFile yamlFile = new YamlFile(new SimpleYamlImplementation(customRepresenter));
// Set your file path
yamlFile.setConfigurationFile("users.yml");
Alternatively, you can also change the default implementation to use your custom representer after you have created the YamlFile:
YamlFile userYaml = new YamlFile("users.yml");
// Set custom key representer
DumperOptions dumperOptions = ((SnakeYamlImplementation) userYaml.getImplementation()).getDumperOptions();
SnakeYamlRepresenter customRepresenter = new CustomKeyRepresenter(dumperOptions);
userYaml.setImplementation(new SimpleYamlImplementation(customRepresenter));
// Same as above comment
// ...
users.yml
users:
192230467519512576:
xp: 100
As stated, keys are yaml strings by default, so numbers are wrapped using single quotes in keys.
For values you can specify the quote style with
set(String, Object, QuoteStyle)
(#50) but not for keys. Maybe you could dump those keys with plain style using a custom snakeyaml representer usingsetImplementation
, but probably is overcomplicating things for your use case.For your second problem, what do you mean
getKeys
returns null? It cannot return null, at least it will be an empty set. ThegetConfigurationSection
returns null if the path is not present in the file.You can check for null to see if the section exists, or use the
isConfigurationSection
method and create a new section withcreateSection
if it does not exist. If you are unsure if the users section exist or want to create it inside your code (instead of providing it as a resource) you could do something like this:YamlFile userYaml = new YamlFile("users.yml"); // Create a new file if not exists, otherwise load its contents userYaml.createOrLoad(); // Get users section if already created ConfigurationSection users = userYaml.getConfigurationSection("users"); if (users == null) { // Create the section if it does not exist users = userYaml.createSection("users"); } // Adding a new user String newUserId = "192230467519512576"; users.set(newUserId + ".xp", 100); // Reading users Set<String> userIds = users.getKeys(false); for (String userId : userIds) { int xp = users.getInt(userId + ".xp"); System.out.println(userId + ": " + xp + " XP"); } // Save changes userYaml.save();
I've excluded exception handling.
Output
192230467519512576: 100 XP
users.yml
users: '192230467519512576': xp: 100
If your file only has users then you could avoid the
users
key entirely, but that's a personal preference.I suggest you to have a look at the serialization example with the
Person
class to see an example of yaml serialization using java objects if you have created aUser
class to wrap the xp and other attributes, allowing you to directly save and retrieve theUser
objects to your yaml file.
The getKeys was giving a nullPointerException but that's simply because I derped out and forgot to load the yaml file. So that's entirely my fault. Thank you for all the help!
I've updated the custom representer example comment above (https://github.com/Carleslc/Simple-YAML/issues/59#issuecomment-1100762648) to work for the latest version 1.8.4, as now the SnakeYamlRepresenter needs the DumperOptions to be passed in the constructor.
I'm setting user's XP and level, using
userYaml.set("users." + user.getId() + ".xp", 0);
This generatesusers: '192230467519512576': xp: 0
Why is it adding single quotes to the user's ID, and how can I change this?