[Info-vax] XML, JSON and YAML, was: Re: Security, support and VMS, was: Re: A new VMS?
Arne Vajhøj
arne at vajhoej.dk
Tue May 4 21:21:23 EDT 2021
On 5/4/2021 4:45 PM, Simon Clubley wrote:
> On 2021-05-04, Arne Vajhøj <arne at vajhoej.dk> wrote:
>> Which of the below are most readable?
>
> JSON, especially if it is formatted in Whitesmiths style.
Really?
The curly brackets and the double quotes make it more readable.
>> XML:
>>
>> <abc>
>> <ab>
>> <a>1</a>
>> <b>2</b>
>> </ab>
>> <c>3</c>
>> </abc>
>>
>
> This has structure, but is really ugly to read.
>
>> JSON:
>>
>> { "ab": {
>> "a": 1,
>> "b": 2
>> },
>> "c" : 3
>> }
>>
>
> This has structure and it is the best of the 3 options.
>
>> YAML:
>>
>> ab:
>> a: 1
>> b: 2
>> c: 3
>
> This is horrible and does not have enough structure to be robust
> against editing errors when being manually edited.
>
> Errors in both XML and JSON can be detected much more reliably
> by a parser than errors in the above YAML example.
You do not write much Python do you?
Using indentation for structure may seem weird for
those familiar with begin end and { }, but that does
not necessarily make it more error prone.
When I dabble a little bit in Python then I don't experience
more problems with improper block structure than in
Pascal or C.
And even if an indentation is wrong then it will typical
result in an error (rather similar to JSON - XML can
be validated against a schema, which does a better
check).
Sometimes it is easier with an example.
I will use Java. I could have used Python, but I know Java
better than Python.
$ type Demo1.java
package yaml;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.yaml.snakeyaml.Yaml;
public class Demo1 {
public static void main(String[] args) {
try {
Yaml parser = new Yaml();
InputStream is = new FileInputStream(args[0]);
Map<String, Object> cfg = (Map<String, Object>)parser.load(is);
is.close();
@SuppressWarnings("unchecked")
Map<String, Object> ab = (Map<String, Object>)cfg.get("ab");
int a = (Integer)ab.get("a");
int b = (Integer)ab.get("b");
int c = (Integer)cfg.get("c");
System.out.printf("%d %d %d\n", a, b, c);
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
$ javac -cp snakeyaml-1_12.jar Demo1.java
Note: Demo1.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ type good1.yaml
ab:
a: 1
b: 2
c: 3
$ java -cp ..:snakeyaml-1_12.jar "yaml.Demo1" good1.yaml
1 2 3
all good, but let us see what happens if the indentation of
the YAML gets messed up.
$ type bad1.yaml
ab:
a: 1
b: 2
c: 3
$ java -cp ..:snakeyaml-1_12.jar "yaml.Demo1" bad1.yaml
java.lang.NullPointerException
at yaml.Demo1.main(Demo1.java:20)
We get an error when we try to get the missing ab.b (because
it was actually just a b).
But it can be even more safe by using some of the more
advanced YAML features.
It is possible to map the config to a strongly typed
object hierarchy instead of the untyped tree.
$ type Demo2.java
package yaml;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.yaml.snakeyaml.Yaml;
public class Demo2 {
public static void main(String[] args) {
try {
Yaml parser = new Yaml();
InputStream is = new FileInputStream(args[0]);
Config cfg = (Config)parser.load(is);
is.close();
int a = cfg.getAb().getA();
int b = cfg.getAb().getB();
int c = cfg.getC();
System.out.printf("%d %d %d\n", a, b, c);
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
$ type Config.java
package yaml;
public class Config {
private AB ab;
private int c;
public AB getAb() {
return ab;
}
public void setAb(AB ab) {
this.ab = ab;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
}
$ type AB.java
package yaml;
public class AB {
private int a;
private int b;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
$ javac -cp snakeyaml-1_12.jar Demo2.java Config.java AB.java
$ type good2.yaml
!!yaml.Config
ab:
a: 1
b: 2
c: 3
$ java -cp ..:snakeyaml-1_12.jar "yaml.Demo2" good2.yaml
1 2 3
And now we get some very specific error messages if we mess
up the indentation.
$ type bad2.yaml
!!yaml.Config
ab:
a: 1
b: 2
c: 3
$ java -cp ..:snakeyaml-1_12.jar "yaml.Demo2" bad2.yaml
Can't construct a java object for tag:yaml.org,2002:yaml.Config;
exception=Cannot create property=b for JavaBean=yaml.Config at 8347192
; Unable to find property 'b' on class: yaml.Config
in 'reader', line 1, column 1:
!!yaml.Config
^
at
org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:333)
at
org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:182)
at
org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:141)
at
org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:127)
at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:481)
at org.yaml.snakeyaml.Yaml.load(Yaml.java:412)
at yaml.Demo2.main(Demo2.java:15)
Caused by: org.yaml.snakeyaml.error.YAMLException: Cannot create
property=b for JavaBean=yaml.Config at 8347192; Unable to find propert
y 'b' on class: yaml.Config
at
org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:299)
at
org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.construct(Constructor.java:189)
at
org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:331)
... 6 more
Caused by: org.yaml.snakeyaml.error.YAMLException: Unable to find
property 'b' on class: yaml.Config
at
org.yaml.snakeyaml.introspector.PropertyUtils.getProperty(PropertyUtils.java:132)
at
org.yaml.snakeyaml.introspector.PropertyUtils.getProperty(PropertyUtils.java:121)
at
org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.getProperty(Constructor.java:308)
at
org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:240)
... 8 more
Arne
More information about the Info-vax
mailing list