Builder Delphi / Lazarus / C ++ แบบง่ายและเล็กสำหรับการแยกวิเคราะห์ 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 ของ Andreas Hausladen
// 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 สตริงสามารถหลบหนีได้ด้วยฟังก์ชั่น Helper McJsonEscapeString() :
N.AsJSON := ' {"path": ' + McJsonEscapeString( ' dirsubdir ' ) + ' } ' ; ผลลัพธ์ใน:
{
"path" : " \ dir \ subdir "
} ในเวอร์ชัน 1.0.6 ได้รับการแนะนำ TJEscapeType enum ที่ใช้ใน McJsonEscapeString() ด้วยระดับการหลบหนีเหล่านี้:
jetNormal : Escapes #8 #9 #10 #12 #13 " jetStrict : ปกติ + /jetUnicode : เข้มงวด + uXXXXjetNone : ความเข้ากันได้ย้อนหลัง ระดับเหล่านี้ได้รับแรงบันดาลใจจากฟังก์ชั่นผู้ช่วยของ Lazarus StringToJSONString() จาก Library 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_EMPY_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 หมายเหตุ : ตั้งแต่การตรวจสอบ 1.0.4 ซอร์สโค้ดของโครงการทดสอบใน Lazarus จึงถูกแปลงเป็น UTF-8 ดังนั้นพารามิเตอร์ asUTF8 จึงถูกตั้งค่าเป็น false
โลกไม่สมบูรณ์แบบและไม่ใช่ฉันนี่คือปัญหาที่รู้จัก:
TMcJsonItem ถูกสร้างอินสแตนซ์ในโครงสร้างลำดับชั้นโดยใช้รายการ fChild มีปัญหาในการสร้างฟิลด์ที่แพร่กระจายโดยอัตโนมัติระหว่างรายการ การแก้ปัญหาภายใต้การศึกษาพยายามที่จะสร้าง TMcJson ระดับผู้ปกครองใหม่ซึ่งวัตถุจะเป็นเหมือนรากและมีวัตถุ TMcJsonItem เป็นเด็ก การทดสอบประสิทธิภาพได้ดำเนินการกับหน่วย myJSON , LkJson , JsonTools และ uJSON ดั้งเดิม นี่คือบทสรุปของการทดสอบ
{... {"keyi":"valuei"}... }และเกี่ยวกับคอมไพเลอร์และเครื่องที่ใช้:
ตารางถัดไปสรุปผลลัพธ์ 1 :
| ห้องสมุด | สร้าง | บันทึก | แยกวิเคราะห์ | โหลด | เข้าถึง | ทั้งหมด |
|---|---|---|---|---|---|---|
McJSON 2 | .11 S | .07 S | .12 S | .09 S | .83 S | 1.25 s |
LkJson 2 | .30 s | .11 S | .47 S | .36 S | .01 S | 1.24 s |
JsonTools | 48.00 s | .70 s | 39.00 s | 40.00 s | .48 S | 1.2 นาที |
myJSON | 50.00 s | .07 S | 5.1 นาที | 7.7 นาที | 1.60 s | 13.1 นาที |
uJSON | 18.6 นาที | 20.1 นาที | 17.5 นาที | 4.31 s | 53.02 S | 57.6 นาที |
McJSONJson->Add("key")->AsString = "value"JsonP->AsJSON = Json->AsJSONLkJsonTlkBalTreedynamic_cast ในการสร้างรหัส VerbosyJson->Add("key", "value")JsonP = dynamic_cast<TlkJSONObject*>(TlkJSON::ParseText(NULL, TlkJSON::GenerateText(NULL, Json)))JsonToolsJson->Add("key", "value")JsonP->Value = Json->AsJsonmyJSONJson->Item["key"]->setStr("value")JsonP->Code = Json->getJSON()uJSONLkJson แต่การคัดค้านของชั้นเรียนก็จะบังคับให้หล่อด้วย dynamic_castuJSON ดูเหมือนว่าจะมีปัญหาด้านประสิทธิภาพที่เกี่ยวข้องกับ toString()Json->put("key", "value")JsonP = new TJSONObject(Json->toString())SaveToFile ไม่มีอยู่ดังนั้นจึงใช้ TStringList->SaveToFile() หลังจากเติม Text ด้วย Json->toString() ตัวชี้วัด: เวลาเฉลี่ยเป็นวินาทีสำหรับการประหารชีวิต 5 ครั้งติดต่อกัน ทั้งหมดคือค่าเฉลี่ยของการทดสอบบางส่วน ผลลัพธ์บางอย่างแปลงเป็นนาที (นาที)
เวอร์ชัน 1.0.5 ปรับปรุงโครงการ JSON 0.9.0 ที่จะเปิดตัวเร็ว ๆ นี้ ↩ 2