Проблемы с созданием правильного файла JSON с использованием суперобъекта или DBXJSON
Я использую Delphi XE2, у меня есть эта структура JSON для создания:
[
{
"Email": "laura@yyyy.com",
"MobileNumber": "",
"MobilePrefix": "",
"Name": "Laura",
"Fields": [
{
"Description": "nominativo",
"Id": "1",
"Value": "Laura"
},
{
"Description": "societa",
"Id": "2",
"Value": ""
},
{
"Description": "idcontatto",
"Id": "3",
"Value": "0"
}
]
},
{
"Email": "paolo@xxxx.com",
"MobileNumber": "",
"MobilePrefix": "",
"Name": "Paolo",
"Fields": [
{
"Description": "nominativo",
"Id": "1",
"Value": "Paolo"
},
{
"Description": "societa",
"Id": "2",
"Value": ""
},
{
"Description": "idcontatto",
"Id": "3",
"Value": "1"
}
]
}
]
Я провел несколько тестов с суперобъектом, но еще не достиг правильного результата, потому что первый элемент массива равен второму. Моя сложность заключается в итерации и оптимизации. Это код, над которым я работаю:
json := TSuperObject.Create;
jsonArray:= TSuperObject.Create(stArray);
json.S['Email'] := 'laura@yyyy.com';
json.S['MobileNumber'] := '';
json.S['MobilePrefix'] := '';
json.S['Name'] := 'Laura';
json['Fields'] := SA([]);
json_Fields:=SO;
json_Fields.S['Description']:='nominativo';
json_Fields.S['Id']:='1';
json_Fields.S['Value']:='Laura';
json.A['Fields'].Add(json_Fields);
json_Fields:=SO;
json_Fields.S['Description']:='societa';
json_Fields.S['Id']:='2';
json_Fields.S['Value']:='';
json.A['Fields'].Add(json_Fields);
//......other fields
JsonArray.AsArray.Add(json);
json.S['Email'] := 'paolo@xxxx.com';
json.S['MobileNumber'] := '';
json.S['MobilePrefix'] := '';
json.S['Name'] := 'Paolo';
json['Fields'] := SA([]);
json_Fields:=SO;
json_Fields.S['Description']:='nominativo';
json_Fields.S['Id']:='1';
json_Fields.S['Value']:='Paolo';
json.A['Fields'].Add(json_Fields);
json_Fields:=SO;
json_Fields.S['Description']:='societa';
json_Fields.S['Id']:='2';
json_Fields.S['Value']:='';
json.A['Fields'].Add(json_Fields);
//......other fields
JsonArray.AsArray.Add(json);
jsonArray.SaveTo('json_mu.txt');
2 ответа
Вы можете использовать нашу сериализацию JSON на основе записей.
Сначала вы определяете запись, содержащую ожидаемый элемент данных и соответствующий динамический массив:
type
TMyRecord: record
Name: string;
Email: string;
MobileNumber: string;
MobilePrefix: string;
Fields: array of record
Id: integer;
Description: string;
Value: string;
end;
end;
TMyRecordDynArray = array of TMyRecord;
Затем вы регистрируете содержание записи:
const // text description of the record layout
__TMyRecord = 'Name,Email,MobileNumber,MobilePrefix string '+
'Fields[Id integer Description,Value string]';
...
TTextWriter.RegisterCustomJSONSerializerFromText(
TypeInfo(TMyRecord),__TMyRecord);
И вы можете загрузить или сохранить данные из / в JSON:
var values: TMyRecordDynArray;
i: integer;
DynArrayLoadJSON(values,pointer(StringToUTF8(text)),TypeInfo(TMyRecordDynArray));
for i := 0 to high(values) do
writeln('name: ',values[i].Name,' mobile: ',values[i].MobilePrefix,' fields count:',length(values[i].Fields));
DynArraySaveJSON(values,TypeInfo(TMyRecordDynArray));
Этот сериализатор JSON будет использовать меньше памяти, чем альтернативы, вероятно, будет быстрее, и у вас будет проверка имен свойств во время компиляции.
Это доступно от Delphi 6 до XE5.
Редактировать:
Например, чтобы заполнить массив:
var R: TMyRecordDynArray;
SetLength(R,2);
with R[0] do begin
Email := 'laura@yyyy.com';
Name := 'Laura';
Setlength(Fields,3);
Fields[0].Description := 'nominativo';
Fields[0].Id := 1;
Fields[0].Value := 'Laura';
Fields[1].Description := 'societa';
Fields[1].Id := 2;
Fields[2].Description := 'idcontatto';
Fields[2].Id := 3;
Fields[2].Value := '0';
end;
with R[1] do begin
Email := 'paolo@xxxx.com';
Name := 'Paolo';
Setlength(Fields,3);
Fields[0].Description := 'nominativo';
Fields[0].Id := 1;
Fields[0].Value := 'Paolo';
Fields[1].Description := 'societa';
Fields[1].Id := 2;
Fields[2].Description := 'idcontatto';
Fields[2].Id := 3;
Fields[2].Value := '1';
end;
json := DynArraySaveJSON(R,TypeInfo(TMyRecordDynArray));
Если вам не нравится with
Заявление, вы можете добавить R[0].
везде. Не главное здесь, я подозреваю.
Я надеюсь, что в свете этого будет показано преимущество использования структуры времени компиляции вместо свойств позднего связывания, определенных как текст (как вы используете SuperObject): вы не ожидаете никаких проблем во время выполнения, с именами свойств или общими логика.
Если ты пишешь json_Fields.S['DescriptioM']:='nominativo'
вы не увидите никакой ошибки в IDE, тогда как Fields[0].DescriptioM := 'nominativo'
не скомпилируется.
Если вы хотите изменить имя свойства, вы можете реорганизовать его в IDE, не забывая ни одного места в вашем коде - оно не скомпилируется.
Если в вашем бизнес-коде используются высокоуровневые структуры Delphi, вам нужно будет вручную написать некоторый подверженный ошибкам код для преобразования этих высокоуровневых значений в / из JSON, используя большинство альтернативных библиотек. В то время как с таким решением вы можете определить свои собственные объекты record
даже добавьте некоторые методы в определение типа и используйте его непосредственно в своем бизнес-коде, не задумываясь о деталях реализации уровня персистентности JSON. Вкратце: вы хотите добавить зависимость к вашей библиотеке JSON в свой бизнес-код? Звучит как нарушение некоторых принципов, которым мы пытаемся следовать при определении кода разработки, управляемого доменом.
Также сравните с кодом, который вы добавили в своем ответе, на предмет читабельности и удобства обслуживания вашего кода.
А также преимущество того, что все неопределенные строковые поля инициализируются с помощью '' по умолчанию (как с любым динамическим массивом).
Edit2:
Как написал Ян в своем собственном ответе, вы можете использовать SuperObject для прямой сериализации записей и динамических массивов, как в случае с нашими классами. Поэтому, если вы не хотите использовать SuperObject, я советую использовать эту функцию и работать с высокоуровневыми типами Delphi. Обратите внимание, что сериализация SuperObject, вероятно, будет медленнее, чем в нашем модуле, и не будет работать со старыми версиями Delphi (тогда как наш модуль работает, например, с Delphi 6/7).
Использование SuperObject:
Определите структуры данных Delphi для работы вместо того, чтобы вручную создавать структуру JSON, затем используйте ToJSON для преобразования объекта Delphi в структуру JSON:
Uses SuperObject;
type
FieldRec = record
ID: Integer;
Description,
Value: String;
end;
FieldArr = Array of FieldRec;
BaseRec = record
Fields: FieldArr;
end;
BaseArr = Array of BaseRec;
OutputObject = class
OutputData: BaseArr;
end;
procedure TFrmAnotherJSONExample.FormShow(Sender: TObject);
var
sObj: ISuperObject;
lFieldArr: FieldArr;
lBaseArr : BaseArr;
lOutputObject: OutputObject;
begin
SetLength(lBaseArr,2);
SetLength(lFieldArr,3);
for i := 0 to 2 do
begin
lFieldArr[i].ID := 10*i;
lFieldArr[i].Description := 'Description' + IntToStr(lFieldArr[0].ID);
lFieldArr[i].Value := 'Name' + IntToStr(lFieldArr[0].ID);
end;
lBaseArr[0].Fields := lFieldArr;
for i := 0 to 2 do
begin
lFieldArr[i].ID := 100*i;
lFieldArr[i].Description := 'Description' + IntToStr(lFieldArr[0].ID);
lFieldArr[i].Value := 'Name' + IntToStr(lFieldArr[0].ID);
end;
lBaseArr[1].Fields := lFieldArr;
lOutputObject := OutputObject.Create;
lOutputObject.OutputData := lBaseArr;
sObj := lOutputObject.ToJSON;
lOutputObject.Free;
Memo1.Lines.Add(sObj.AsJSON(true));
end;
Выход из вышеперечисленного:
{
"OutputData": [
{
"Fields": [
{
"Description": "Description0",
"ID": 0,
"Value": "Name0"
},{
"Description": "Description0",
"ID": 100,
"Value": "Name0"
},{
"Description": "Description0",
"ID": 200,
"Value": "Name0"
}]
},
{
"Fields": [
{
"Description": "Description0",
"ID": 0,
"Value": "Name0"
},{
"Description": "Description0",
"ID": 100,
"Value": "Name0"
},{
"Description": "Description0",
"ID": 200,
"Value": "Name0"
}]
}]
}
Таким образом, вы получите именованные массивы, я предполагаю, что это хорошо (и я бы порекомендовал это).
Кроме того, он имеет внешний {}, который определяет объект JSON.
Добавлено: сразу после публикации я вижу, что я забыл заполнить поля Email, MobileNumber и т. Д., Но это теперь тривиально, и я оставляю это в качестве упражнения для читателя;-)