digitalmars.D.learn - How to parse a json node that contains children of different types?
- Bagomot (37/37) Jul 20 2021 I have a json like this:
- Mathias LANG (59/62) Jul 20 2021 IIUC, the `arguments` are command line arguments passed to a Java
- Bagomot (8/25) Jul 20 2021 Thank you! From your answer, I realized that in fact, I would
- Steven Schveighoffer (5/10) Jul 21 2021 Not [jsoniopipe](https://github.com/schveiguy/jsoniopipe). In that case,...
I have a json like this: ```json { "arguments":{ "jvm":[ { "rules":[ { "action":"allow", "os":{ "name":"osx" } } ], "value":[ "-XstartOnFirstThread" ] }, "-Djava.library.path=${natives_directory}" ] } } ``` Here the "jvm" node is an array that has different data types for its elements (json object and string). I am using [asdf](https://code.dlang.org/packages/asdf) library to deserialize json. I am trying to deserialize this json into a structure like this: ```d struct Arguments{ serdeKeys("jvm") Object[] jvm; } ``` But there is a problem with different types. I understand that Object[] is not suitable here, but I don’t know how to do it. I ask you to help me with this.
Jul 20 2021
On Tuesday, 20 July 2021 at 21:18:12 UTC, Bagomot wrote:But there is a problem with different types. I understand that Object[] is not suitable here, but I don’t know how to do it. I ask you to help me with this.IIUC, the `arguments` are command line arguments passed to a Java program, and some of those might be passed to the JVM ? So you probably will end up with something like: ``` struct Arguments{ JVMArgs jvm; ProgramArgs program; } ``` Of course, the question is, what's `JVMArgs` ? Now, as you noticed, you can't represent an array of unrelated types in D (which makes sense). So what you can do is create a common type for it, by using an `union`. ``` union JVMArg { RuleValue ruleValue; string str; // Etc... } alias JVMArgs = JVMArg[]; ``` However, \<YOUR-JSON-LIBRARY> might not support it directly, or might support it through its own type (you will need a tagged union, and not just a simple union, as you need to know the type that the library read). But if you take a step back, I think you might find this solution is far from ideal. Having worked on a JSON library myself, I can tell you they are all implemented with a tagged union. And converting a tagged union to a tagged union is no improvement. Instead, I would recommend to just use the JSON directly. If you need to pass things around, you might want to deserialize it to a common format. For example, assuming your project is a process manager for Java program and you want to read a common set of arguments from a configuration file, you might want to just generate the strings: ``` auto myJSON = parseConfigFile("config.json"); string[] defaultJVMArgs = parseJVMArgs(myJSON); auto processMonitor = new ProcessMonitor(defaultJVMArgs); ``` TL;DR: If you want to use loosely typed data in a strongly typed language, you need to come up with a common type. That common type is usually either a discriminated union (which a JSON object is, essentially) or something that is domain-specific. Hope this helps. I had a quick look at asdf and couldn't see a support for tagged union, so you would probably need to provide your data structure with a `deserializeFromAsdf` method. If you want to do so, look into providing a wrapper to `SumType`, e.g.: ``` struct MyUnion (T...) { SumType!T data; alias data this; SerdeException deserializeFromAsdf(Asdf data) { /* Fill in the SumType */ } ``` But I would recommend just using the JSON object if you can.
Jul 20 2021
On Wednesday, 21 July 2021 at 03:00:51 UTC, Mathias LANG wrote:TL;DR: If you want to use loosely typed data in a strongly typed language, you need to come up with a common type. That common type is usually either a discriminated union (which a JSON object is, essentially) or something that is domain-specific. Hope this helps. I had a quick look at asdf and couldn't see a support for tagged union, so you would probably need to provide your data structure with a `deserializeFromAsdf` method. If you want to do so, look into providing a wrapper to `SumType`, e.g.: ``` struct MyUnion (T...) { SumType!T data; alias data this; SerdeException deserializeFromAsdf(Asdf data) { /* Fill in the SumType */ } ``` But I would recommend just using the JSON object if you can.Thank you! From your answer, I realized that in fact, I would rather do the parsing of these arguments myself. Before using asdf, I tried to do the same with the standard std.json. The problem is the same there. I agree that this is logical for D. I was also interested in SumType, I will try to do something with it for experience.
Jul 20 2021
On 7/20/21 11:00 PM, Mathias LANG wrote:But if you take a step back, I think you might find this solution is far from ideal. Having worked on a JSON library myself, I can tell you they are all implemented with a tagged union. And converting a tagged union to a tagged union is no improvement.Not [jsoniopipe](https://github.com/schveiguy/jsoniopipe). In that case, you could use a specialized type with a `fromJSON` static member to do whatever you wanted. -Steve
Jul 21 2021