Delphi / Lazarus / C ++ Builder فئة بسيطة وصغيرة لتحليل JSON السريع.
بعض نقاط الاهتمام:
McJSON ) ، فئة واحدة فقط ( TMcJsonItem ). uses
McJSON;
...
function Test99 (out Msg: string): Boolean;
var
Json: TMcJsonItem;
i: Integer;
begin
Msg := ' Test: Github readme.md content ' ;
Json := TMcJsonItem.Create();
try
try
// add some pairs.
Json.Add( ' key1 ' ).AsInteger := 1 ;
Json.Add( ' key2 ' ).AsBoolean := True;
Json.Add( ' key3 ' ).AsNumber := 1.234 ;
Json.Add( ' key4 ' ).AsString := ' value 1 ' ;
// add an array
Json.Add( ' array ' , jitArray);
for i := 1 to 3 do
Json[ ' array ' ].Add.AsInteger := i;
// save a backup to file
if (Json[ ' array ' ].Count = 3 ) then
Json.SaveToFile( ' test99.json ' );
// remove an item
Json.Delete( ' array ' );
// oops, load the backup
if (Json.Count = 4 ) then
Json.LoadFromFile( ' test99.json ' );
// test final result
Result := (Json.AsJSON = ' {"key1":1,"key2":true,"key3":1.234,"key4":"value 1","array":[1,2,3]} ' );
except
Result := False;
end ;
finally
Json.Free;
end ;
end ; سوف تنتج testtest99.json :
{
"key1" : 1 ,
"key2" : true ,
"key3" : 1.234 ,
"key4" : " value 1 " ,
"array" : [
1 ,
2 ,
3
]
}# include " McJson.hpp "
...
bool Test99 (AnsiString& Msg)
{
bool Result;
TMcJsonItem* Json = NULL ;
Msg = " Test: Github readme.md content " ;
Json = new TMcJsonItem ();
try
{
try
{ // add some pairs.
Json-> Add ( " key1 " )-> AsInteger = 1 ;
Json-> Add ( " key2 " )-> AsBoolean = true ;
Json-> Add ( " key3 " )-> AsNumber = 1.234 ;
Json-> Add ( " key4 " )-> AsString = " value 1 " ;
// add an array
Json-> Add ( " array " , jitArray);
for ( int i = 1 ; i <= 3 ; i++)
Json-> Values [ " array " ]-> Add ()-> AsInteger = i;
// save a backup to file
if (Json-> Values [ " array " ]-> Count == 3 )
Json-> SaveToFile ( " test99.json " );
// remove an item
Json-> Delete ( " array " );
// oops, load the backup
if (Json-> Count == 4 )
Json-> LoadFromFile ( " test99.json " );
// test final result
Result = (Json-> AsJSON ==
" { " key1 " :1, " key2 " :true, " key3 " :1.234, " key4 " : " value 1 " , " array " :[1,2,3]} " );
}
catch (...)
{
Result = false ;
}
}
__finally
{
if (Json) delete (Json);
}
return (Result);
} يرجى اتفاقية قراءة اختبارات الوحدة في مجلد test للحصول على قائمة كاملة من حالات استخدام McJSON .
فقط استخدم خاصية AsJSON
var
N: TMcJsonItem;
begin
N := TMcJsonItem.Create;
N.AsJSON := ' {"i": 123, "f": 123.456, "s": "abc", "b": true, "n": null} ' ;
// use N here
N.Free;
end ; إذا كنت تريد التحقق مما إذا كانت سلسلة JSON صالحة:
Answer := N.Check( ' {"i":[123} ' ); // Answer will be false لن تثير طريقة Check أي استثناء. المثال أعلاه سوف يلتقط Error while parsing text: "expected , got }" at pos "10" استثناء. إذا كنت بحاجة إلى التقاط الاستثناءات وإدارتها ، فاستخدم CheckException مثل:
try
Answer := N.CheckException( ' {"k":1, "k":2} ' ); // Answer will be false
except
on E: Exception do
begin
// Error while parsing text: "duplicated key k" at pos "11"
end ;
end ; يتيح McJSON طريقة بسيطة للوصول إلى العناصر من خلال المسارات. يمكننا استخدام '/' أو '' أو '.' كما فواصل المسار.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// access and change second object's value
N.Path( ' o.k2 ' ).AsString := ' value2 ' ;نتيجة في:
{
"o" : {
"k1" : " v1 " ,
"k2" : " value2 "
}
} لاحظ أن Path() لا يقبل الفهارس بعد ، مثل هذا:
N.AsJSON := ' {"o": [{"k1":"v1"}, {"k2":"v2"}] ' ;
N.Path( ' o[1].k2 ' ).AsString := ' value2 ' ; نظرًا لأن الإصدار 1.0.4 يسمح McJSON باستخدام مختصرات الممتلكات كما هو الحال في أندرياس هاوسلادين كائنات بيانات JSON.
// access (automatic creation as in JDO)
Obj.S[ ' foo ' ] := ' bar ' ;
Obj.S[ ' bar ' ] := ' foo ' ;
// array creation, Obj is the owner of 'array'
Obj.A[ ' array ' ].Add.AsInteger := 10 ;
Obj.A[ ' array ' ].Add.AsInteger := 20 ;
// object creation, 'array' is the owner of ChildObj
ChildObj := Obj[ ' array ' ].Add(jitObject);
ChildObj.D[ ' value ' ] := 12.3 ;
// array creation, ChildObj is the owner of 'subarray'
ChildObj.A[ ' subarray ' ].Add.AsInteger := 100 ;
ChildObj.A[ ' subarray ' ].Add.AsInteger := 200 ;نتيجة في:
{
"foo" : " bar " ,
"bar" : " foo " ,
"array" :[
10 ,
20 ,
{
"value" : 12.3 ,
"subarray" :[
100 ,
200
]
}
]
}فيما يلي كيفية الوصول إلى جميع العناصر (الأطفال) لكائن JSON وتغيير نوع القيمة والمحتوى.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// type and value: from string to integer
for i := 0 to N[ ' o ' ].Count- 1 do
N[ ' o ' ].Items[i].AsInteger := i+ 1 ; نتيجة في:
{
"o" : {
"k1" : 1 ,
"k2" : 2
}
} يمكننا استخدام خصائص Items[index] Values['key'] للوصول إلى العناصر داخل الكائنات والصفائف. منذ الإصدار 0.9.5 ، يمكننا استخدام At(index, 'key') أو At('key', index) كاختصار.
N.AsJSON := ' {"a": [{"k1":1,"k2":2},{"k1":10,"k2":20}]} ' ;
// how to access k2 of second object.
i := N[ ' a ' ].Items[ 1 ].Values[ ' k2 ' ].AsInteger; // i will be equal to 20
i := N[ ' a ' ].Items[ 1 ][ ' k2 ' ].AsInteger; // uses the Values[] as default property
i := N[ ' a ' ].At( 1 , ' k2 ' ).AsInteger; // shortener: index, key
i := N.At( ' a ' , 1 )[ ' k2 ' ].AsInteger; // shortener: key, index وهناك استخدامات أخرى بدون المعلمة key :
N.AsJSON := ' {"k1":1,"k2":2,"k3":3,"k4":4} ' ;
i := N.Items[ 2 ].AsInteger; // i will be equal to 3
i := N.At( 2 ).AsInteger; // shortener: just index
i := N.At( ' k3 ' ).AsInteger; // shortener: just keyباستخدام Delphi Enumerator ، يمكنك تصفح الأطفال والقيم الخاصة بالعنصر.
var
N, item: TMcJsonItem;
begin
N := TMcJsonItem.Create;
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
for item in N[ ' o ' ] do
// use item here, e.g. item.Key, item.Value, item.AsStringتغيير جميع قيم كائن مع عناصر متعددة. ليس شائعا هناك.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
N[ ' o ' ].AsString := ' str ' ;نتيجة في:
{
"o" : {
"k1" : " str " ,
"k2" : " str "
}
} وإذا كان من الضروري تغيير نوع o :
N[ ' o ' ].ItemType := jitValue;
N[ ' o ' ].AsString := ' str ' ;نتيجة في:
{
"o" : " str "
}تحويل من صفيف إلى نوع الكائن والعكس بالعكس. أيضا ، ليس شائعا هناك.
N.AsJSON := ' { "k1": ["1", "2"], "k2": {"1": "a", "2": "b"} } ' ;
N[ ' k1 ' ].ItemType := jitObject; // convert array to object with items
N[ ' k2 ' ].ItemType := jitArray ; // convert object with items to array نتيجة في:
{
"k1" : {
"0" : " 1 " ,
"1" : " 2 "
},
"k2" : [
" a " ,
" b "
]
}أدخل بعض العناصر باستخدام المفاتيح والموقف.
P.Insert( ' c ' , 0 ).AsInteger := 3 ;
P.Insert( ' b ' , 0 ).AsInteger := 2 ;
P.Insert( ' a ' , 0 ).AsInteger := 1 ;نتيجة في:
{
"a" : 1 ,
"b" : 2 ,
"c" : 3
}أيضا ، من الممكن إدراج الكائنات في المصفوفات.
Q.AsJSON := ' {"x":0} ' ;
P.ItemType := jitArray;
P.Insert(Q, 1 );نتيجة في:
[
1 ,
{
"x" : 0
},
2 ,
3
] هام : منذ الإصدار 0.9.3 ، Add() و Insert() سوف يستنسخ وسيط من النوع TMcJsonItem . لذلك ، يتعين علينا تحرير الذاكرة لـ Q أيضًا:
P.Free;
Q.Free; نظرًا لأن الإصدار 1.0.5 يمكن الهروب من السلاسل مع وظيفة المساعد McJsonEscapeString() :
N.AsJSON := ' {"path": ' + McJsonEscapeString( ' dirsubdir ' ) + ' } ' ; نتيجة في:
{
"path" : " \ dir \ subdir "
} في الإصدار 1.0.6 تم تقديم تعداد TJEscapeType المستخدم في McJsonEscapeString() مع مستويات الهروب هذه:
jetNormal : Escapes #8 #9 #10 #12 #13 " .jetStrict : عادي + / .jetUnicode : صارمة + uXXXX .jetNone : التوافق المتخلف. هذه المستويات مستوحاة من سلسلة وظائف Lazarus ' StringToJSONString() من مكتبة FPJSON.
دعونا نرى كيفية فحص جميع بنية البيانات الداخلية وأنواع وقيم كائن TMcJsonItem .
// ---------------------------------------------------------------------------
void
TFormMain::Inspect (TMcJsonItem* AMcJItem, AnsiString Ident)
{
if (!AMcJItem) return ;
// log current
MyLog ( Ident + ItemToStr (AMcJItem) );
// log child
if ( AMcJItem-> HasChild )
{
Ident = " " + Ident;
for ( int i= 0 ; i < AMcJItem-> Count ; i++)
{ // use Value not Child because are note using Key[].
Inspect ( AMcJItem-> Items [i], Ident );
}
}
}
// ---------------------------------------------------------------------------
String
TFormMain::ItemToStr (TMcJsonItem* AMcJItem) const
{
String Ans = " " ;
if (AMcJItem)
Ans = AMcJItem-> GetTypeStr () +
" ; " + AMcJItem-> GetValueStr () +
" ; Key= " + AMcJItem-> Key +
" ; Value= " + AMcJItem-> Value +
" ; JSON= " + AMcJItem-> AsJSON ;
return (Ans);
}
// --------------------------------------------------------------------------- واستخدام مثال مثل testInspect.json :
{
"foo" : " bar " ,
"array" : [
100 ,
20
],
"arrayObj" : [
{
"key1" : 1.0
},
{
"key2" : 2.0
}
],
"Msg" : [
" #1 UTF8 example: motivação " ,
" #2 Scapes: btnfr\ uFFFF "\ "
]
} استدعاء Inspect() مع كائن Json محمل مع testInspect.json :
TMcJsonItem* Json = new TMcJsonItem();
if (Json)
{
Json-> LoadFromFile ( " testInspect.json " );
Inspect (Json);
delete (Json);
}نتيجة في:
object; string; Key=; Value=; JSON={"foo":"bar","array":[100,20],"arrayObj":[{"key1":1.0},{"key2":2.0}],"Msg":["#1 UTF8 example: motivação","#2 Scapes: btnfru"\"]}
value; string; Key=foo; Value=bar; JSON="foo":"bar"
array; string; Key=array; Value=; JSON="array":[100,20]
value; number; Key=; Value=100; JSON=100
value; number; Key=; Value=20; JSON=20
array; string; Key=arrayObj; Value=; JSON="arrayObj":[{"key1":1.0},{"key2":2.0}]
object; string; Key=; Value=; JSON={"key1":1.0}
value; number; Key=key1; Value=1.0; JSON="key1":1.0
object; string; Key=; Value=; JSON={"key2":2.0}
value; number; Key=key2; Value=2.0; JSON="key2":2.0
array; string; Key=Msg; Value=; JSON="Msg":["#1 UTF8 example: motivação","#2 Scapes: btnfruFFFF"\"]
value; string; Key=; Value=#1 UTF8 example: motivação; JSON="#1 UTF8 example: motivação"
value; string; Key=; Value=#2 Scapes: btnfruFFFF"\; JSON="#2 Scapes: btnfruFFFF"\"
منذ الإصدار 0.9.0 ، سيتم تحليل المفاتيح الفارغة والتحقق من أخطاء مع وجود أخطاء:
N.AsJSON := ' {"": "value"} ' ; وسيقوم ToString() بإنتاج كائن JSON صالح:
{
"" : " value "
}داخليًا ، ستستخدم سلسلة ثابتة C_EMPTY_KEY كمحتوى لحقل FKEY.
منذ الإصدار 0.9.2 ، سيتم تحليل الأوتار مع عدم هروب استراحة الخط مع الأخطاء:
N.AsJSON := ' {"key": "value ' + # 13 + ' "} ' ;سوف يثير استثناء:
Error while parsing text: "line break" at pos "14"
يمكن أن يتم تحميل McJSON من ملفات ASCII و UTF-8 (مع أو بدون BOM). انظر طريقة LoadFromFile . سوف تكتب طريقة SaveToFile باستخدام ترميز UTF-8. ملاحظة : منذ Vertion 1.0.4 ، تم تحويل رمز المصدر لمشروع الاختبار في Lazarus إلى UTF-8 ، وبالتالي تم تعيين معلمة asUTF8 على false .
العالم ليس مثاليًا ولا أنا أولاً. إليك بعض المشكلات المعروفة:
TMcJsonItem تم إنشاء مثيل لها في الهيكل الهرمي باستخدام قوائم fChild ، فهناك مشكلة لإنشاء حقول تنتشر تلقائيًا بين العناصر. يحاول حل قيد الدراسة إنشاء فئة أولياء جديدة TMcJson التي ستكون الكائنات مثل الجذور ولديها كائنات TMcJsonItem كأطفالها. تم إجراء اختبار الأداء مع وحدات myJSON الأصلية و LkJson و JsonTools و uJSON . هنا ملخص للاختبارات.
{... {"keyi":"valuei"}... }وحول المترجم والآلة المستخدمة:
يلخص الجدول التالي النتائج 1 :
| مكتبة | يولد | يحفظ | تحليل | حمولة | وصول | المجموع |
|---|---|---|---|---|---|---|
McJSON 2 | .11 ق | .07 ق | .12 ق | .09 ق | .83 ق | 1.25 ق |
LkJson 2 | .30 ق | .11 ق | .47 ق | .36 ق | .01 ق | 1.24 ق |
JsonTools | 48.00 ق | .70 ق | 39.00 ق | 40.00 ق | .48 ق | 1.2 دقيقة |
myJSON | 50.00 ق | .07 ق | 5.1 دقيقة | 7.7 دقيقة | 1.60 ق | 13.1 دقيقة |
uJSON | 18.6 دقيقة | 20.1 دقيقة | 17.5 دقيقة | 4.31 ق | 53.02 ق | 57.6 دقيقة |
McJSONJson->Add("key")->AsString = "value" .JsonP->AsJSON = Json->AsJSON .LkJsonTlkBalTree .dynamic_cast جعل الفعل الرمز.Json->Add("key", "value") .JsonP = dynamic_cast<TlkJSONObject*>(TlkJSON::ParseText(NULL, TlkJSON::GenerateText(NULL, Json))) .JsonToolsJson->Add("key", "value") .JsonP->Value = Json->AsJson .myJSONJson->Item["key"]->setStr("value") .JsonP->Code = Json->getJSON() .uJSONLkJson ، لكن كولون الفئات سيجبر أيضًا على التقاط dynamic_cast .uJSON ، يبدو أن هناك مشكلة في الأداء تتعلق بـ toString() .Json->put("key", "value") .JsonP = new TJSONObject(Json->toString()) .SaveToFile غير موجود ، لذلك استخدم TStringList->SaveToFile() بعد ملء Text مع Json->toString() . المقياس: متوسط الوقت في الثواني (S) ل 5 عمليات إعدام متتالية. المجموع هو متوسط الاختبارات الجزئية. بعض النتائج تحولت إلى دقائق (دقيقة). ↩
الإصدار 1.0.5. تحسين اختبار JSON 0.9.0 مشروع سيتم إصداره قريبًا. ↩ ↩ 2