לעבוד עם JSON ו FPC

FPC מגיע עם תמיכה מאוד חזקה בJSON. המימוש הוא מימוש טבעי ואינו תלוי בספרייה כלשהי. החלטתי להציג כיצד אפשר לעבוד איתו על קצה המזלג. לקח לי כרבע שעה מהרגע שהחלטתי שאני רוצה ללמוד לעשות את זה, עד שקיבלתי את התוצר שאתם רואים. כמובן שלפני כן, לא היה לי ניסיון בכלל לעבוד עם הספרייה המגיעה עם FPC. ואם זה לא מספיק, השתמשתי ב kate המגיע עם KDE ולא ב Lazarus לפיתוח – מה שלקח ממני קצת יותר זמן.

הספרייה עצמה מגיעה עם מספר יחידות. היחידה הבסיסית והנדרשת כמעט תמיד היא fpJSON, אשר מספקת לנו אובייקטים המתאימים ל json עצמו. יש את jsonscanner אשר נבנה בשביל לפרש קבצי json. זהו מפרש לקסאלי. יש את jsonparser אשר נועד לפרש את המידע מ jsonscanner ולהעביר אותו לאובייקטים המוגדרים ב fpJSON.

בנוסף, הספרייה מגיעה עם fpJSONRTTI אשר ממיר אובייקטים באמצעות RTTI ל JSON וממיר חזרה מ JSON לאובייקטים. בנוסף מגיעה בספרייה גם יחידה בשם jsonconf בשביל לעבוד עם קבצי הגדרות מבוססי json.

אז כיצד אני יוצר מחרוזת JSON מאובייקטי פסקל אתם בטח שואלים. הנה קוד פשוט:

program create_json;
{$mode objfpc}
uses fpjson, SysUtils;

var
  json : TJSONObject;

begin
  json := TJsonObject.Create;
  try
    json.add('Hello', 'World');
    json.add('TheAnswerForWorldUniverseAndEverything', 42);
    json.add('Array', TJSONArray.Create(['a', 1, 3.14]));
    writeln('JSON: ', json.AsJSON);
  except
    on e:EJSON do
      writeln(stderr, 'Unable to create json: ', e.message);
  end;
FreeAndNil(json);
end.

יצרנו מחלקה מסוג  TJSONObject אשר בעצם מייצגת "אובייקט" של JSON בתקן עצמו. משם הוספנו איבר מסוג מחרוזת, איבר מסוג מספר שלם ומאיבר מסוג מערך. המערך מכיל בתוכו גם מחרוזת, גם מספר שלם וגם מספר עשרוני.

בשביל להיות בטוחים שהעבודה נעשתה כמו שצריך, אנחנו תופסים אותה לחריגות כלשהם, ובמידה והתיה בעיה, אז אנחנו נציג עליה מידע.

לפרש קובץ json זה עוד יותר פשוט, אבל יש משהו קטן שצריך לשים לב אליו:

program parse_json;
{$mode objfpc}
uses fpjson, jsonparser, SysUtils, classes;

var
  parser    : TJSONParser;
  json_file : TFileStream;
  json      : TJSONData;

begin
  json_file := TFileStream.Create('/tmp/test.json', fmOpenRead);
  json_file.position := 0;
  parser := TJSONParser.create(json_file);
  try
    json := parser.Parse;
    writeln('JSON: ', json.AsJSON);
  except
    on e:EJSONParser do
      writeln(stderr, 'Unable to parse JSON: ', e.message);
  end;
  FreeAndNil(json);
  FreeAndNil(parser);
  FreeAndNil(json_file);
end.

הסיבה שאנחנו שמים את המידע שמחוזר אלינו כאובייקטי JSON ומשחררים לבד, הוא בגלל שParse היא פונקציה אשר יוצרת עבורינו במיוחד אובייקט מוכן, אבל היא לא מנהלת אותו, אלא מעבירה אלינו את הניהול, מה שאומר שאנחנו אחראים לשחרר את הזיכרון כאשר אנחנו מפסיקים להשתמש בו. חשוב להבין כי זה אומר שאנחנו יכולים לשחרר את המפרש מוקדם יותר מאשר שחרור האובייקט שקיבלנו.

עוד דבר חשוב, הוא לדעת לתפוס שגיאות במידה ויש בזמן ניסיון קריאת הקובץ והניסיון לפרש אותו. במידה ולא נעשה זאת, התכנית שלנו תמות לפני זמנה.

7 מחשבות על “לעבוד עם JSON ו FPC

    1. ik_5 מאת

      אני לא מסכים איתו. nil הוא לא תוספת אשר לא צריך אותה. זה לא מדבר על שחרור, זה מדבר על בדיקה. נגיד ואעשה if assigned… אז אם האובייקט עבר free אבל הוא לא nil, אז לרוב assgined יכנס, אבל אין לו מה להריץ, ואז במקרה הטוב אקבל AccessViolation ובמקרה הרע, יהיה לי code execution שאני לא אהיה מודע אליו. nil בא ואומר כי לא רק ששחררתי את הזכרון, אלא אני לא מצביע לשום דבר. ואם אני לא מצביע לשום דבר ולא שחררתי זיכרון, אז יש לי דליפת זיכרון, ואם שחררתי אבל לא עבדתי עם nil, ויש מצב שאבדוק אם האובייקט מאותחל, אז אני צפוי במקרה הטוב לחריגה שתעצור את הריצה, ובמקרה הרע אני מחביא לעצמי באג כלשהו.

      זו לפחות דעתי בניסיון שיש לי. אה, ובלזרוס הוסיפו ל lclproc את FreeThenNil, שהוא לדעתי הגיוני יותר לשימוש🙂

      1. עידו גנדל

        FreeThenNil – רעיון נחמד!🙂

        אני יודע שהשמת nil מבטיחה ש-Assigned ייתן תשובה מועילה… אבל ניק טוען בפוסט שלו שזה בדיוק העניין: שבתכנון נכון לא מגיעים בכלל למצב שצריך לשאול אם אובייקט הוא Assigned (הפונקציה עצמה עדיין שימושית, רק לא למטרה הספציפית הזאת).

        ארתיום – זו פעם ראשונה שאני שומע על מתקפה שמבוססת על פוינטרים תועים. זה בהחלט מעניין ותודה על הקישור, אם כי אני עדיין לא בטוח שזה סותר את הטיעון שבפוסט – כי "בתכנון הנכון" אתה הרי לא תיגש לעולם לאובייקט ששחררת (בניגוד לפונקציות וירטואליות שמוזכרות בוויקיפדיה ושם באמת יש סיכון).

        1. ik_5 מאת

          אני אולי זקן מידי, אבל אני למדתי לא לסמוך על עצמי לא לעשות טעויות ולא לעשות באגים. וזה עוד לפני לדעת מי אולי ישתמש בקוד שלי. אני לא חושב שאני יכול "לתכנן נכון" או בעיקר לסמוך על זה. עדיף לעשות עוד צעד ולשים כ nil, מאשר להתעורר יום אחד ולגלות באג שקיים מהיום הראשון שהסתרת אותו. אבל זה רק אני כמובן🙂

          1. ik_5 מאת

            הבעיה היא שהוא חושב בגישה אקדמית מידי. תניח שתמיד המצב יהיה אופטימלי, ואני מעולם לא עבדתי במצב אופטימלי עד היום. אצלי תמיד מישהו היה לחוץ על העבודה, תמיד קורים מצבים שאני נוגע בקוד שלא ראיתי שנתיים וצריך פתאום לתחזק אותו, ואין הרבה זמן …
            הגישה שלו לא מתאימה למציאות, ואין לה קשר לפסקל או דלפי, אלא לחשיבה שלדעתי דומה מידי לאקדמיה

כתיבת תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s