نموذج كائن JSON سريع الكفاءة في الذاكرة ، مع دعم لتحليل وكتابة بكفاءة في تنسيق متوافق مع JSON.
تعتمد هذه المكتبة فقط على مستودع Neslib. يتم تضمينه كوحدة فرعية مع هذا المستودع.
نقطة الدخول الرئيسية لهذه المكتبة هي واجهة IJsonDocument . يتم استخدامه لتحليل مستندات JSON وتحميله وحفظه ويوفر الوصول إلى نموذج كائن JSON. يمكنك تحليل سلسلة JSON على النحو التالي:
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.Parse( ' { "Answer" : 42 } ' );
end ;لاحظ أنه ، على عكس مواصفات JSON الرسمية ، لا تتطلب هذه المكتبة عروض أسعار حول مفاتيح القاموس (طالما أن المفتاح لا يحتوي على مسافات أو شخصيات أخرى غير هوية). لذا فإن ما يلي صالح أيضًا:
Doc := TJsonDocument.Parse( ' { Answer : 42 } ' ); يمكنك أيضًا استخدام طريقة Load للتحميل من ملف أو دفق.
على جانب الإخراج ، يمكنك استخدام Save للحفظ في ملف أو دفق ، أو ToJson للإخراج إلى سلسلة JSON.
يمكنك أيضًا إنشاء مستندات JSON جديدة من نقطة الصفر باستخدام أساليب CreateArray أو CreateDictionary :
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ;كما ترون في هذا المثال ، يمكنك الوصول إلى نموذج كائن مستند JSON من خلال خاصية الجذر.
في قلب نموذج كائن JSON هو نوع TJsonValue . هذا هو السجل الذي يمكن أن يحتفظ بأي نوع من قيمة JSON.
يوفر العديد من مشغلي التحويل الضمني لتحويل TJsonValue إلى نوع آخر (Delphi). بالإضافة إلى ذلك ، هناك العديد To* الطرق التي تحاول تحويل TJsonValue ولكن إرجاع القيمة الافتراضية المقدمة في حالة فشل التحويل.
أنت (يمكنك) أبدًا إنشاء TJsonValue بنفسك ؛ الطريقة الوحيدة لإنشاء TJsonValue هي إضافة قيمة إلى صفيف أو قاموس JSON:
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ; يضيف هذا المثال TJsonValue (مع القيمة 42) إلى مجموعة JSON. لإنشاء مجموعة جديدة من القاموس ، يمكنك استخدام أساليب AddArray أو AddDictionary بدلاً من ذلك:
var
Doc: IJsonDocument;
Dict: TJsonValue;
begin
Doc := TJsonDocument.CreateArray;
Dict := Doc.Root.AddDictionary;
Dict.AddOrSetValue( ' answer ' , 42 );
end ;هذا يخلق قاموسًا جديدًا ويضيفه إلى صفيف الجذر. ثم ، تتم إضافة القيمة 42 إلى هذا القاموس تحت اسم "الإجابة".
للتحقق من نوع القيمة ، استخدم خاصية TJsonValue.ValueType أو واحدة من طرق TJsonValue.Is* .
عند محاولة استخدام طرق مثل Add (أو AddOrSetValue ) على القيم التي لا تكون صفائف (أو قواميس) ، سيتم رفع استثناء.
ومع ذلك ، فإن الوصول إلى العناصر الموجودة في صفيف (باستخدام خاصية Items ) أو القيم الموجودة في القاموس (باستخدام خاصية Values ) لن يؤدي أبدًا إلى استثناء ، حتى لو كان فهرس الصفيف خارج الحدود. يسمح ذلك بسلسلة مجموعة من الصفيف/القاموس المتعددة معًا دون الاضطرار إلى التحقق من صحة كل خطوة وسيطة. على سبيل المثال:
I := Doc.Root.Items[ 3 ].Values[ ' foo ' ].Values[ ' bar ' ].Items[ 4 ].ToInteger( 0 );سينجح هذا دائمًا ، لكن إرجاع 0 إذا لم يكن أي من القيم المتوسطة متوفرة.
تجعل واجهة IJsonDocument من السهل قراءة وكتابة JSON في نموذج كائن المستند.
ومع ذلك ، يمكنك أيضًا اختيار قراءة أو كتابة JSON يدويًا إذا كنت تفضل (على سبيل المثال لتجنب الاضطرار إلى تحميل نموذج كائن في الذاكرة). يمكنك القيام بذلك مع واجهات IJsonReader و IJsonWriter في وحدة Neslib.Json.IO .
هذه الواجهات مستقلة تمامًا عن أي تطبيق DOM ولا تتطلب حتى وحدة Neslib.Json . استخدام هذه الواجهات أكثر تعقيدًا قليلاً ويتطلب بعض العمل. انظر وحدة Neslib.Json.IO لمزيد من المعلومات.
هناك أيضًا تطبيق JsonPath الذي يشبه XPath يمكنك استخدامه للاستعلام عن مستندات JSON.
لا توجد مواصفات JSONPATH رسمية ، ولكن يبدو أن الإصدار الأكثر استخدامًا هو الذي طوره ستيفان غوسنر.
يشبه jsonpath:
$.store.book[0].titleأو
$['store']['book'][0]['title'] كلا التمثيلين متطابقان: يمكنك استخدام إما تدوين DOT ( . ) أو قوس ( [] ) للإشارة إلى أطفال القاموس. يمكن أيضًا استخدام الأقواس مع مؤشرات رقمية للدلالة على أطفال صفيف حسب الفهرس.
يستخدم JsonPath فقط عروض أسعار فردية (') داخل قوسين. نسمح أيضًا بالاقتباسات المزدوجة (") نظرًا لأن هذه أسهل في سلاسل دلفي.
باختصار:
$ الذي يشير إلى الجذر ، يليه صفر أو أكثر من مشغلي الأطفال ( . أو [] ). A $ في حد ذاته يطابق المستند بأكمله.* أو '*' ) لتتناسب مع جميع الأطفال. على سبيل المثال ، $.store.book[*].author مع مؤلفي جميع الكتب في المتجر.. ) ، يمكن استخدام نقطة مزدوجة ( .. ) للبحث عن أي أحفاد بدلاً من الأطفال المباشرين. على سبيل المثال ، $..author جميع المؤلفين ، بغض النظر عن العمق. وهذا ما يسمى الهبوط العودية.$.store.book[0,2,3] الكتب الأولى والثالثة والرابعة.[Start:End:Step] لمطابقة شريحة (نطاق) من الأطفال. هذا يطابق جميع الأطفال من الفهرس Start حتى (ولكن ليس بما في ذلك) End ، باستخدام حجم Step معين (عادة 1). كلها اختيارية ، ولكن يجب إعطاء قيمة واحدة على الأقل (والقولون):Start ، فمن الضمني أن تكون 0. القيمة السالبة تشير إلى إزاحة من نهاية الصفيف.End ، فإن شريحة مستخلصات خلال نهاية الصفيف. تشير القيمة السالبة إلى وتعويض من نهاية الصفيف.Step ، فمن المفترض أن تكون 1.List[2:] تطابق العناصر الثالثة وجميع العناصر التالية.List[-2:] تطابق آخر عنصرين.List[:2] يطابق العنصرين الأولين.List[:-2] يطابق كل العنصرين الماضيين.List[2:-2] تطابق جميع العناصر ولكن الأولين والأخير اثنين.List[-4:-2] تتطابق مع العناصر الثالثة والرابعة من النهاية.List[::2] تطابق جميع العناصر مع فهرس متساو.لدى JsonPath أيضًا مشغل @ للسماح بتعبيرات مخصصة للنص. نحن لا ندعم هذا المشغل.
مثال وثيقة:
{ "store" : {
"book" : [
{ "category" : " reference " ,
"author" : " Nigel Rees " ,
"title" : " Sayings of the Century " ,
"price" : 8.95
},
{ "category" : " fiction " ,
"author" : " J. R. R. Tolkien " ,
"title" : " The Lord of the Rings " ,
"isbn" : " 0-395-19395-8 " ,
"price" : 22.99
}
],
"bicycle" : {
"color" : " red " ,
"price" : 19.95
}
}
}مثال مسارات:
| تعبير | نتيجة |
|---|---|
$ | يطابق المستند الجذر (قيمة واحدة) |
$..* | يطابق جميع الأعضاء في المستند (الكثير من القيم) |
$.store.book[*].author | مؤلفو جميع الكتب في المتجر |
$..author | جميع المؤلفين |
$.store.* | كل الأشياء في المتجر (كتابان ودراجة) |
$.store..price | سعر كل شيء في المتجر |
$..book[2] | الكتاب الثالث |
$..book[-1:] | الكتاب الأخير بالترتيب |
$..book[:2] | أول كتابين |
API Jsonpath قصيرة وبسيطة. يتكون من سجل TJsonPath مع اثنين فقط من الطرق.
للمطابقة لمرة واحدة ، استخدم طريقة Match الثابتة:
var
Doc: IJsonDocument;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Matches := TJsonPath.Match(Doc, ' $.store.book[*].author ' );
end ;إذا كنت تخطط لاستخدام نفس المسار على مستندات متعددة (فرعية) ، فسيكون ذلك أسرع في تحليل المسار مرة واحدة ، ثم تطبيقه عدة مرات:
var
Doc1, Doc2: IJsonDocument;
Path: TJsonPath;
Matches1, Matches2: TArray<TJsonValue>;
begin
Doc1 := TJsonDocument.Load(...);
Doc2 := TJsonDocument.Load(...);
Path := TJsonPath.Create( ' $.store.book[*].author ' );
Matches1 := Path.Match(Doc1);
Matches2 := Path.Match(Doc2);
end ;يمكنك أيضًا تشغيل المسار على الأشجار الفرعية:
var
Doc: IJsonDocument;
Store: TJsonValue;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Store := Doc.Root.Values[ ' store ' ];
Matches := TJsonPath.Match(Store, ' $.book[*].author ' );
end ; إذا كنت مهتمًا فقط بمباراة واحدة (أو الأولى) ، فيمكنك استخدام MatchSingle بدلاً من ذلك:
var
Doc: IJsonDocument;
Match: TJsonValue;
begin
Doc := TJsonDocument.Load(...);
if (TJsonPath.MatchSingle(Store, ' $.book[*] ' , Match)) then
...
end ; جميع إدارة الذاكرة في مكتبة JSON هذه تلقائي. تمتلك واجهة IJsonDocument جميع TJsonValue وتدمرها عند تدمير المستند (تخرج عن النطاق).
الشيء الوحيد الذي تحتاج إلى إدراكه هو أنه يجب ألا تستخدم أي سجلات TJSONVALUE بعد أن تم تدمير المستند. القيام بذلك سيؤدي إلى سلوك غير محدد وربما تعطل.
يمكنك تخصيص بعض السلوك باستخدام هذه التعريفات الشرطية:
JSON_UTF8 : لاستخدام UTF8String بدلاً من String في كل مكان. سيتم التعامل مع جميع الأوتار كسلاسل 8 بت UTF-8 بدلاً من سلاسل Unicode 16 بت. هذا يقلل من استهلاك الذاكرة ويسرع تحليله قليلاً. ومع ذلك ، هذا يعني أنه سيتعين عليك استخدام مكتبة JSON هذه مع UTF8STRINGS أيضًا ، وإلا فإن Delphi ستحول ضمنيًا بين سلاسل Unicode و UTF8Strings ، والتي يمكن أن تؤذي الأداء.JSON_STRING_INTERNING : لتمكين سلسلة متداخلة لمفاتيح القاموس. هذا يقلل من استهلاك الذاكرة في حالة استخدام نفس المفتاح في كثير من الأحيان (وهو أمر شائع عندما يتم تصدير JSON من قاعدة بيانات) ، ولكنه أبطأ قليلاً. تعلن وحدة neslib.json عن نوع JsonString String أو UTF8String ، اعتمادًا على تعريف JSON_UTF8 . ومع ذلك ، هذا لا يعني أنه يجب عليك استخدام JsonString أيضًا. إذا كنت لا تهتم بتحديد JSON_UTF8 ، فيمكنك فقط استخدام سلاسل منتظمة مع هذه المكتبة.
Neslib.json مرخصة بموجب ترخيص BSD المبسط.
انظر الترخيص. txt للحصول على التفاصيل.