Einzelnen Beitrag anzeigen

mytbo

Registriert seit: 8. Jan 2007
461 Beiträge
 
#11

AW: JSON -> Database -> Auswertung ?

  Alt 8. Mai 2022, 14:47
Um dem Demonstrator einen nützlichen Aspekt zu geben und neben DocVariant eine weitere Klasse, die mORMot Text-Writer Klassen, vorzustellen, im folgendem ein funktionales Beispiel.
Berücksichtigte JSON Varianten:
  • {"Value": "value0"}
  • [{"Value": "value0"},{"Value": "value1"}]
  • [{"Value": "value0"},{},{"Value": "value1"}]
Disclaimer: Das Beispiel ist ein Proof of Concept, der Sourcecode ist weder getestet noch optimiert.
Delphi-Quellcode:
procedure ConvertJsonToCsv(const pmcJsonFileName: TFileName; const pmcCsvFileName: TFileName = ''; const pmcFilterFields: TRawUtf8DynArray = []);

  //-------- local functions ------------------------------------------

  procedure GetFieldNames(const pmcData: Variant; pmFieldNames: PRawUtf8DynArray; const pmcFilterFields: TRawUtf8DynArray);
  var
    fieldName: RawUtf8;
    docObject: PDocVariantData;
  begin
    SetLength(pmFieldNames^, 0);
    docObject := _Safe(pmcData);
    case docObject^.Kind of
      dvObject:
        ;
      dvArray:
        if docObject^.Count > 0 then
          docObject := _Safe(docObject^.Value[0])
        else
          Exit; //=> leeres Array
      else
        Exit; //=> dvUndefined
    end;

    for var i: Integer := 0 to High(docObject^.Names) do
    begin
      fieldName := docObject^.Names[i];
      if FindPropName(pmcFilterFields, fieldName) < 0 then
        AddRawUtf8(pmFieldNames^, fieldName, True, False);
    end;
  end;

  function VariantObjectToCsv(const pmcData: Variant; const pmcFieldNames: TRawUtf8DynArray): RawUtf8;
  var
    docObject: PDocVariantData;
    tmpBuffer: TTextWriterStackBuffer;
  begin
    docObject := _Safe(pmcData);
    if docObject^.Kind <> dvObject then Exit; //=>

    with TJsonWriter.CreateOwnedStream(tmpBuffer) do
    try
      for var i: Integer := 0 to High(pmcFieldNames) do
      begin
        AddVariant(docObject^.Value[pmcFieldNames[i]], twNone);
        AddComma;
      end;

      CancelLastComma;
      SetText(Result);
    finally
      Free;
    end;
  end;

  //-------- end local functions --------------------------------------

var
  jsonData: Variant;
  fieldNames: TRawUtf8DynArray;
  csvFileName: TFileName;
begin
  if not TDocVariantData(jsonData).InitJsonFromFile(pmcJsonFileName, JSON_OPTIONS_FAST_EXTENDED) then Exit; //=>

  GetFieldNames(jsonData, @fieldNames, pmcFilterFields);
  if Length(fieldNames) = 0 then Exit; //=>

  csvFileName := pmcCsvFileName;
  if csvFileName = 'then
    csvFileName := ChangeFileExt(pmcJsonFileName, '.csv');

  with TTextWriter.CreateOwnedFileStream(csvFileName) do
  try
    // Header schreiben
    AddString(RawUtf8ArrayToCsv(fieldNames));
    AddCR;

    // CSV Daten schreiben
    if TDocVariantData(jsonData).Kind = dvArray then
    begin
      for var i: Integer := 0 to TDocVariantData(jsonData).Count - 1 do
      begin
        AddString(VariantObjectToCsv(TDocVariantData(jsonData)[i], fieldNames));
        AddCR;
      end;
    end
    else
      AddString(VariantObjectToCsv(jsonData, fieldNames));

    FlushToStream;
  finally
    Free;
  end;
end;


var
  timer: TPrecisionTimer;
begin
  timer.Start;
  ConvertJsonToCsv('_listData.json', '', ['DasWillIchNicht', 'UndDasAuchNicht']);
  WriteLn(Format('Total time: %s', [timer.Stop]));
end;
Für 100K Objekte wird ca. 100ms benötigt. Für eine Variante, die tolerant gegenüber dem Eingangsformat ist, die mORMot Funktionen "out of the box" verwendet, gar kein schlechter Wert.

Bis bald...
Thomas
  Mit Zitat antworten Zitat