B4J Tutorial [B4X]Convert Complex Structures of Lists and Maps to YAML Strings: can also be used to convert JSON to YAML.

[B4X]Convert Complex Stuctures of Lists and Maps to YAML Strings: can also be used to convert JSON to YAML.

In my endless pursuit of knowledge, I have been experimenting with VPS servers.
I came across various API standards. The OpenAPI web site has examples of JSON API strings that could be used in a standard way.
The interesting part is that they display the protocol strings in JSON format but also in YAML format - something I was not familiar with.

https://spec.openapis.org/oas/latest.html (scroll down to relevant section)

Coming from struggling with the myriad of nested brackets of Java and Javascript to the beauty of B4X code,
I was happy to see that the brackets of JSON are gone in the equivalent YAML! YAML format is a pleasure to read.
@Erel wrapped a YAML parser:

https://www.b4x.com/android/forum/threads/b4x-YAML-parser.129461/
https://github.com/EsotericSoftware/YAMLbeans

While the YAML writer is part of the github source, the writer part is not exposed in the wrapper.
However, once you have a B4X structure of maps and lists it is not hard to render it in YAML format.

This is what I did. There were some gotchas, but it didn't take long.
In general you can use it to display any complex structure in a (this) human readable format.

To convert JSON to YAML, you parse the JSON, and then use the "structureToYAML" sub to convert the map/list structure to YAML.
The gotcha is that the JSON parser preserves order in lists but not in keys - look at the code to see how I restored key order.
While key order does not affect the functionality of JSON, it makes it much easier to compare JSON with YAML strings.

As a bonus, I have included in the attached file a .bjl .bal .bil reader that converts these files to YAML format.
It is based on the BalConverter written by @Erel. I modified it slightly to return a map object which is then converted into a YAML string.

https://www.b4x.com/android/forum/t...e-layouts-files-to-json-and-vice-versa.41623/

The converter sub (structureToYAML) does all the work and is not splatform specific.
The demo in the attached .zip file has 5 examples that can be viewed.
The demo app can also be used as a standalone app to paste JSON from the clipboard and copy the YAML to the clipboard.

I have tested the demo in B4J and B4A but it needs modification to work in B4i.
The layout file example relies on BalConverter, which only works in B4j. I disabled the example in B4A.

In a recent post by @aeric I saw a large, unusual JSON string. It was very difficult to understand its structure.
After converting this JSON to YAML preserving key order, the structure becomes clear. I added it as an example in the demo.

If you try it and find errors or omissions, let me now in this thread. I'll make corrections.

example3.png
 

Attachments

  • toYaml3.zip
    29.3 KB · Views: 43
Last edited:

aeric

Expert
Licensed User
Longtime User
Trying in B4J.
There are a few changes I need to make.

1. Setting the Windows size to fix my screen.
B4X:
#Region Project Attributes
    '#MainFormWidth: 1400
    '#MainFormHeight: 800
    #MainFormWidth: 1280
    #MainFormHeight: 600
#End Region

2. Copy the sample files (jsonsamples.txt and test1.bjl) from B4A Files to B4J Objects.

3. Optional
B4XMainPage (Line 298):
source(1) = $"Source File: YAML\B4J\Objects\test1.bjl"$
 

William Lancee

Well-Known Member
Licensed User
Longtime User
Thanks @aeric
I have reduced the expected size of the screen and moved the examples to "..\files\" in B4J.
I have updated the demo project in post #1.
 

aeric

Expert
Licensed User
Longtime User
moved the examples to "..\files\" in B4J
I got error if I put the files in Files folder and use File.DirAssets.
B4X:
Waiting for debugger to connect...
Program started.
Error occurred on line: 27 (WiLBalReader)
java.io.FileNotFoundException: AssetsDir\test1.bjl (The system cannot find the path specified)
    at java.base/java.io.RandomAccessFile.open0(Native Method)
    at java.base/java.io.RandomAccessFile.open(RandomAccessFile.java:346)
    at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:260)
    at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:214)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.Initialize2(RandomAccessFile.java:89)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:673)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:240)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)

I suggest modify the code for line #31 in B4XMainPage to:
B4XMainPage (line 31):
MyDir = File.DirApp.SubString2(0, File.DirApp.Length - "Objects".Length) & "Files"
and line #298 in B4XMainPage
B4XMainPage (Line 298):
source(1) = $"Source File: ${MyDir}\test1.bjl"$
 

William Lancee

Well-Known Member
Licensed User
Longtime User
@aeric
Done.

It is far too easy to rely on one's own folder structure.
This time I did attach toYaml3.zip to post #1

Thanks again
 
Last edited:
Top