I would like to find out that the top object is named "SomeJSON" and has two children.
True. I treat that as the "document", as the other formats (YAML, XML, Ini, Text) don't have such an extra wrapper. They are removed automatically, because the tokenizer strips them and calls itself if there was only one element:I would like to find out that the top object is named "SomeJSON" and has two children.
Just to be clear: in your specific example the top object has no name and has a single member SomeJSON (the top could after all also be an array for example).
TJSONData deals with values, not names. There doesn't seems to be an easy way to get the name of the top object and a list of the names of the children. It is assumed you already know them, and know what type of data structure (Value, Array, Object) it is.
function TNode.SplitJSON(ThisText: string; var IsArr: Boolean): TStringArray; var sl: TStringList; s: string; c: Char; b: Boolean; i, Inside, Start: Integer; begin IsArr := False; SetLength(Result, 0); if Empty(ThisText) then Exit; sl := TSTringList.Create; ThisText := Trim(ThisText); Start := 1; Inside := 0; for i := 1 to Length(ThisText) do begin c := ThisText[i]; if (c = '{') or (c = '[') then Inc(Inside) else if (c = '}') or (c = ']') then Dec(Inside); if ((c = ',') or (i = Length(ThisText))) and (Inside = 0) then begin s := Trim(System.Copy(ThisText, Start, i - Start + 1)); Start := i + 1; if s[Length(s)] = ',' then s := Trim(System.Copy(s, 1, Length(s) - 1)); sl.Add(s); end; end; if sl.Count = 1 then begin s := sl[0]; if (s[1] = '[') Then IsArr := True; if ((s[1] = '[') or (s[1] = '{')) and ((s[Length(s)] = ']') or (s[Length(s)] = '}')) then begin s := Trim(System.Copy(s, 2, Length(s) - 2)); sl.AddStrings(SplitJSON(s, b), True); end; end; Result := sl.ToStringArray; sl.Free; end;
Hey SymbolicFrank,
in your code, lines 23 and 23, the way you put it may induce in issues
If the string contains, for example, "{[]]", you'll have an Inside=0 at the end, but the JSON is not valid.
Cheers,
Gus
Ok, improvements can be made. The tokenizer uses multiple passes. And indeed, if the JSON is invalid, it breaks. But it's pretty simple and it works well.
To explain what I'm doing: I have to communicate with a large REST API (thousands of functions with often large data structures). That's a lot of work to implement. And it changes frequently. They do have description files, in RAML and OpenAPI. That's both YAML. So, it seems to be best to parse that and generate a big node tree, that contains all the functions, enums and data structures, and the references between them. Which is what I did. Which wasn't easy, because almost every text is valid YAML. It's very unstructured.
You get the parameters and body belonging to a function (by name), fill them in and call the function. Those parts are serialized and send to the webservice, the response is turned into another node tree. Which you then can process. I'm thinking of adding a DataSet interface as well.
That way, it is fully dynamic and I don't have to make (or generate) a class for each data structure, and can automate calling them.
And as it turns out, I've written most of that myself. There is no FP YAML, RAML or OpenAPI parser that I know of. Or extended, serializable nodes. I do use library functions and objects, of course. TSTringlist, some containers from Generics.Collections, Variants, LazUTF8 and fphttpclient. And I follow all the conventions, my classes look the same and have the same methods as the default ones.
For the other side of the application, I made some custom variants of default Lazarus components, like TDbf. And a large library of helper functions, of course. I did post a few bugfixes on the bugtracker, and I have more, but the last one is not accepted yet, so I have forked my own libraries.
That's how you do it, right?
And treating components as black boxes is fine, if they do what you want them to do. If not, you need another one or write your own.
//...
Which is what I made.
OpenAPI schema can be in YAML and JSON format. If you only have YAML schema then there are conversion tools to JSON.
Some time ago I made a simple OpenAPI client framework with an object generator. If you are interested I will create a repository on github.
Here you have a repo:
https://github.com/michalgw/PasOAPI
Here you have a repo:
https://github.com/michalgw/PasOAPI
A few remarks:
1. only supports a subset of OpenAPI types.
2. requires FPC trunk (uses custom attributes and extended rtti)
3. supports OpenAPI schema version 2 (or even earlier, I don't remember...), of course in JSON format
4. you need to implement your own "TPOConnector" class
5. "import" folder contains code generation tool
Could I just trouble you to add content on the About section and probably drop a README.md file?First I will try to refactor code and add OAPI v3 support. Then I will add examples and a short instruction. This project was developed as a "quick and dirty" solution, but since I have made it public, I feel obligated to improve the quality of this code.
Thanks. It looks great, but unfortunately I cannot translate the YAML to JSON. I tried a few converters, three become unresponsive or do nothing, one gives an error: "Invalid YAML".Have you tried the Swagger Editor?
But I'm sure I'll have to attach more APIs in the future, so it will be useful when I come across one that uses JSON OpenAPI.
First I will try to refactor code and add OAPI v3 support. Then I will add examples and a short instruction. This project was developed as a "quick and dirty" solution, but since I have made it public, I feel obligated to improve the quality of this code.
Have you tried the Swagger Editor?
https://editor.swagger.io/ (https://editor.swagger.io/)
It is an OAPI schema editor and has ability to write schema to JSON.