#1 2024-03-20 18:18:15

gidesa
Member
Registered: 2024-03-20
Posts: 3

Field extraction with path in unit syncrossplatformJson

Hello,
I am using your very good syncrossplatformJson unit to process Json data.
But I have not found a mode to extract a field using a dot path.
For example, with this Json:
{"obj":{"primo":12,"secondo":"abcd",
  "terzo":{"val":"A123","valnum":"85","valfloat":"98.6"}
  }
}

how I can obtain 98.6 passing path 'obj.terzo.valfloat'?
Something as:

Var
v: variant;
jsonOb: variant;
begin
  // create the Json variant
  ...
  v:=JsonFromPath(jsonOb, 'obj.terzo.valfloat');
end;

Offline

#2 2024-03-20 18:56:21

igors233
Member
Registered: 2012-09-10
Posts: 241

Re: Field extraction with path in unit syncrossplatformJson

Try with _Safe(JsonOb).GetValueByPath(...

Offline

#3 2024-03-20 19:09:29

gidesa
Member
Registered: 2024-03-20
Posts: 3

Re: Field extraction with path in unit syncrossplatformJson

Thank you, but in SynCrossPlatformJSON.pas there is no function GetValueByPath,
nor _Safe class.
Note that I am using the unit stand alone, not with the entire Mormot framework.

Offline

#4 2024-03-21 06:18:55

igors233
Member
Registered: 2012-09-10
Posts: 241

Re: Field extraction with path in unit syncrossplatformJson

Sorry, I've missed part of you using CrossPlatform unit, there's likely nothing ready for it. Try to copy GetValueByPath from SynCommons or mormot.core.variants

Offline

#5 2024-03-21 12:23:21

gidesa
Member
Registered: 2024-03-20
Posts: 3

Re: Field extraction with path in unit syncrossplatformJson

Hello, at end I wrote a simple recursive method, JSONFromPath, added to TJsonVariantData record.
Maybe it could be added to unit.
Regards


// ------------ Code ---------------------------------------------------------------------
  TJSONVariantData = record
......
  public
......
    // Recursively search and extract a Json element, object, array or simple types
    // having as input a path, ex. "fielda.fieldb.fieldc"
    function JSONFromPath(const path: string): Variant;
......
implementation
.....

function TJSONVariantData.JSONFromPath(const path: string): Variant;
var
  i: Integer;
  res, resJson: Variant;
begin
  Result:=Variants.Null;
  if (Variant(Self)= variants.Unassigned) or (Variant(Self)=Variants.Null) then
  begin
    Exit;
  end;
  i := Pos('.',Path);
  if i=0 then
  begin
    res:=  Self.Value[path] ;
    if (res = Variants.Unassigned) then
    begin
      Exit;
    end;
    if  VarIsStr(res) or  VarIsType(res, vtAnsiString) or VarIsType(res, vtWideString) then
        Result:=VarToStr(res)
    else
    begin
      resJson:=JSONVariant(res);
      if (TJSONVariantData(resJson).Kind in [jvObject, jvArray]) then
        Result := resJson
      else
        Result:=res;
    end;
  end else begin
    Result := TJSONVariantData(JSONVariant(Self.Value[Copy(path,1,i-1)])).JSONFromPath(Copy(path, i+1)  );
  end;
end;

// --------------------  Tests
var
  doc, newItem, newItem2: Variant;


  doc.obj:=JSONVariant('{}');
  doc.obj.primo:=12;
  doc.obj.secondo:='abcd';
  newItem:=JSONVariant('{"val": "A123", "valnum": "85", "valfloat": "98.6"}');
  doc.obj.terzo:=newItem;
 


  newItem2:=TJSONVariantData(doc).JSONFromPath('obj.terzo');
  js:=newItem2;
  writeln('obj.terzo: ',js);
  newItem2:=TJSONVariantData(doc).JSONFromPath('obj.terzo.val');
  js:=newItem2;
  writeln('obj.terzo.val: ',js);
  newItem2:=TJSONVariantData(doc).JSONFromPath('obj.terzo.valnum');
  js:=newItem2;
  Writeln('obj.terzo.valnum: ',js);
  newItem2:=TJSONVariantData(doc).JSONFromPath('obj.terzo.valfloat');
  js:=newItem2;
  Writeln('obj.terzo.valfloat: ',js);
  // not existing
  newItem2:=TJSONVariantData(doc).JSONFromPath('obj.terzo.none');
  js:=BoolToStr(VarIsNull( newItem2), True);
  Writeln('Not existing: ',js);

Offline

Board footer

Powered by FluxBB