From 6a0dee6583f77b8e856b3d339c9ecfd289d4ecda Mon Sep 17 00:00:00 2001
From: michael <michael@freepascal.org>
Date: Wed, 27 Sep 2017 18:02:02 +0000
Subject: [PATCH] * Simple JSON -> YAML converter

git-svn-id: trunk@37333 -
---
 .gitattributes                     |   2 +
 packages/fcl-json/examples/j2y.pp  |  52 +++++++++
 packages/fcl-json/fpmake.pp        |   6 +
 packages/fcl-json/src/json2yaml.pp | 171 +++++++++++++++++++++++++++++
 4 files changed, 231 insertions(+)
 create mode 100644 packages/fcl-json/examples/j2y.pp
 create mode 100644 packages/fcl-json/src/json2yaml.pp

diff --git a/.gitattributes b/.gitattributes
index 35feb337a4..ce05aaa01f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2542,6 +2542,7 @@ packages/fcl-json/examples/confdemo.pp svneol=native#text/plain
 packages/fcl-json/examples/demoformat.pp svneol=native#text/plain
 packages/fcl-json/examples/demortti.pp svneol=native#text/plain
 packages/fcl-json/examples/ini2json.pp svneol=native#text/plain
+packages/fcl-json/examples/j2y.pp svneol=native#text/plain
 packages/fcl-json/examples/parsedemo.lpi svneol=native#text/plain
 packages/fcl-json/examples/parsedemo.pp svneol=native#text/plain
 packages/fcl-json/examples/simpledemo.lpi svneol=native#text/plain
@@ -2551,6 +2552,7 @@ packages/fcl-json/src/README.txt svneol=native#text/plain
 packages/fcl-json/src/fpjson.pp svneol=native#text/plain
 packages/fcl-json/src/fpjsonrtti.pp svneol=native#text/plain
 packages/fcl-json/src/fpjsontopas.pp svneol=native#text/plain
+packages/fcl-json/src/json2yaml.pp svneol=native#text/plain
 packages/fcl-json/src/jsonconf.pp svneol=native#text/plain
 packages/fcl-json/src/jsonini.pp svneol=native#text/plain
 packages/fcl-json/src/jsonparser.pp svneol=native#text/plain
diff --git a/packages/fcl-json/examples/j2y.pp b/packages/fcl-json/examples/j2y.pp
new file mode 100644
index 0000000000..60343c25a2
--- /dev/null
+++ b/packages/fcl-json/examples/j2y.pp
@@ -0,0 +1,52 @@
+{
+    This file is part of the Free Component Library
+    Copyright (c) 2017 by Michael Van Canneyt michael@freepascal.org
+
+    JSON To YAML syntax converter demo
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+program j2y;
+{$MODE OBJFPC}
+{$H+}
+
+uses fpjson,classes, jsonparser,json2yaml,sysutils;
+
+Var
+  IFN,OFN : String;
+  D : TJSONData;
+  IFS,OFS : TStream;
+  jtoy : TJSONToYaml;
+
+
+begin
+  If ParamCount=0 then
+    writeln('Usage j2y infile [outfile]');
+  IFN:=ParamStr(1);
+  OFN:=ParamStr(2);
+  if OFN='' then
+    OFN:=Changefileext(IFN,'yaml');
+  D:=Nil;
+  OFS:=Nil;
+  jtoy:=Nil;
+  IFS:=TFileStream.Create(IFN,fmOpenRead or fmShareDenyWrite);
+  try
+    D:=GetJSON(IFS);
+    OFS:=TFileStream.Create(OFN,fmCreate);
+    JTOY:=TJSONToYaml.Create;
+    JTOY.Convert(D,OFS);
+  finally
+    D.Free;
+    IFS.Free;
+    OFS.Free;
+    JTOY.Free;
+  end;
+
+end.
+
diff --git a/packages/fcl-json/fpmake.pp b/packages/fcl-json/fpmake.pp
index 5ab781ade0..9f4da71180 100644
--- a/packages/fcl-json/fpmake.pp
+++ b/packages/fcl-json/fpmake.pp
@@ -82,12 +82,18 @@ begin
       AddUnit('fpjson');
       AddUnit('jsonparser');
      end;
+    T:=P.Targets.AddUnit('json2yaml.pp');
+    with T.Dependencies do
+      begin
+      AddUnit('fpjson');
+     end;
 
     P.ExamplePath.Add('examples');
     T:=P.Targets.AddExampleProgram('confdemo.pp');
     T:=P.Targets.AddExampleProgram('parsedemo.pp');
     T:=P.Targets.AddExampleProgram('simpledemo.pp');
     T:=P.Targets.AddExampleProgram('ini2json.pp');
+    T:=P.Targets.AddExampleProgram('j2y.pp');
 
     // simpledemo.lpi
     // confdemo.lpi
diff --git a/packages/fcl-json/src/json2yaml.pp b/packages/fcl-json/src/json2yaml.pp
new file mode 100644
index 0000000000..26003892fc
--- /dev/null
+++ b/packages/fcl-json/src/json2yaml.pp
@@ -0,0 +1,171 @@
+{
+    This file is part of the Free Component Library
+    Copyright (c) 2017 by Michael Van Canneyt michael@freepascal.org
+
+    JSON To YAML syntax converter
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+unit json2yaml;
+
+{$MODE OBJFPC}
+{$H+}
+
+interface
+
+uses classes,fpjson;
+
+Type
+
+  { TJSONToYaml }
+
+  TJSONToYaml = class
+  Private
+    FAddHeader: Boolean;
+    FIndent : String;
+    FIndentSize: integer;
+    FOutput : TStream;
+    FLineBreak : String;
+    FIndentAdd : String;
+  Protected
+    Function Indent(S :String): Integer;
+    Procedure ConvertNull;
+    Procedure ConvertBoolean(JSON : TJSONBoolean);
+    Procedure ConvertArray(JSON : TJSONArray);
+    procedure ConvertObject(JSON: TJSONObject);
+    Procedure ConvertNumber(JSON : TJSONNumber);
+    Procedure ConvertString(JSON : TJSONString);
+    Procedure DoConvert(JSON : TJSONData);
+    procedure Push(S: TJSONStringType);
+    Property TheOutput : TStream Read Foutput;
+  Public
+    Procedure Convert(JSON : TJSONData; aOutput : TStream);
+    Property AddHeader : Boolean Read FAddHeader Write FAddHeader;
+    Property IndentSize: Integer Read FIndentSize Write FIndentSize;
+  end;
+
+implementation
+
+procedure TJSONToYaml.Push(S : TJSONStringType);
+
+begin
+  if (Findent<>'') then
+    Foutput.WriteBuffer(Findent[1],Length(Findent));
+  S:=S+FLineBreak;
+  Foutput.WriteBuffer(S[1],Length(S));
+  Findent:=StringOfChar(' ',Length(FIndent));
+end;
+
+procedure TJSONToYaml.ConvertNumber(JSON: TJSONNumber);
+
+begin
+  Push(JSON.AsString);
+end;
+
+procedure TJSONToYaml.ConvertString(JSON: TJSONString);
+begin
+  Push(JSON.AsString);
+end;
+
+function TJSONToYaml.Indent(S: String): Integer;
+begin
+  Result:=Length(FIndent);
+  if (S='') then
+    S:=FIndentAdd;
+  Findent:=Findent+S;
+end;
+
+procedure TJSONToYaml.ConvertNull;
+begin
+  Push('null');
+end;
+
+procedure TJSONToYaml.ConvertBoolean(JSON: TJSONBoolean);
+begin
+  If JSON.AsBoolean then
+    Push('true')
+  else
+    Push('false');
+end;
+
+procedure TJSONToYaml.ConvertArray(JSON: TJSONArray);
+
+Var
+  l,i : Integer;
+
+begin
+  L:=Length(Findent);
+  try
+    For I:=0 to JSON.Count-1 do
+      begin
+      Indent('- ');
+      DoConvert(JSON.Items[i]);
+      SetLength(Findent,L);
+      end;
+  finally
+    SetLength(Findent,L);
+  end;
+end;
+
+procedure TJSONToYaml.ConvertObject(JSON: TJSONObject);
+
+Var
+  I,L : Integer;
+  D : TJSONData;
+  N : TJSONStringType;
+
+begin
+  L:=Length(FIndent);
+  try
+    For I:=0 to JSON.Count-1 do
+      begin
+      D:=JSON.Items[I];
+      N:=JSON.Names[I];
+      if D.JSONType in fpjson.StructuredJSONTypes then
+        begin
+        Push(N+': ');
+        Indent('');
+        end
+      else
+        Indent(N+': ');
+      DoConvert(D);
+      SetLength(Findent,L);
+      end
+  finally
+    SetLength(Findent,L);
+  end;
+end;
+
+procedure TJSONToYaml.Convert(JSON: TJSONData; aOutput: TStream);
+
+begin
+  If FIndentSize=0 then
+    FIndentSize:=2;
+  Findent:='';
+  FIndentAdd:=StringOfChar(' ',FIndentSize);
+  FLineBreak:=sLineBreak;
+  FOutput:=AOUtput;
+  if AddHeader then
+    Push('---');
+  DoConvert(JSON);
+end;
+
+procedure TJSONToYaml.DoConvert(JSON: TJSONData);
+begin
+  Case JSON.JSONType of
+    jtArray : convertArray(JSON as TJSONArray);
+    jtObject : convertObject(JSON as TJSONObject);
+    jtString : convertString(JSON as TJSONString);
+    jtNull : ConvertNull;
+    jtNumber : ConvertNumber(JSON as TJSONNumber);
+    jtBoolean : ConvertBoolean(JSON as TJSONBoolean);
+  end;
+end;
+
+end.