המשימה שלימדה אותי לכבד את השטחה נראתה משעממת בכרטיס: " ייצא את אובייקט ההגדרות לגיליון אלקטרוני כדי שהלקוח יוכל לערוך אותו." ההגדרות היו כתם JSON מקונן עמוק מתוך תצורה של Laravel, שלוש וארבע רמות בעומק המקומות, עם מערכים של דגלי תכונה מעורבבים בגיליון אלקטרוני יש עמודות, לא עצים. הייתי צריך כל ערך עלה כמפתח שטוח יחיד שהלקוח יכול לראות בשורה אחת, לערוך ולהחזיר, ואז הייתי צריך לבנות מחדש את המבנה המקונן המדויק מהעריכות שלהם מבלי לאבד אינדקס מערך אחד. הנסיעה הלוך ושוב, מקוננת לשטוח ושטוח בחזרה לקונן, היא מה שעושה משטח JSON, והשגתו ללא הפסדים היא כל המשחק. The Toolz משטח JSON הוא הכלי שבניתי לעבודה ההיא, והמדריך הזה מסביר איך זה עובד ואיפה זה מציל אותך.
TL;DR: משטח JSON ממיר אובייקט מקונן לאובייקט ברמה אחת שהמפתחות שלו הם הנתיב לכל ערך, אז
{"user":{"city":"Austin"}}הופך{"user.city":"Austin"}. מערכים משתטחים עם האינדקס שלהם בנתיב (roles.0). Unflatten הופך אותו, בונה מחדש את האובייקטים והמערכים המקוננים מאותם מפתחות מנוקדים. הכלי Toolz עושה את שני הכיוונים ללא אובדן, משמר אובייקטים ומערכים ריקים, תומך בסימון מערך נקודות או סוגריים ובמפריד מותאם אישית, ופועל כולו בצד הלקוח ללא העלאה וללא הרשמה.
אני בונה SaaS על Laravel ו - React ומשלוח תוספים של וורדפרס, כך JSON מקונן נמצא בכל מקום ביום שלי: קבצי תצורה, מטענים API, קטלוגים של הודעות i18n, חנויות של דגלי תכונה המערכות שצורכות את המטענים האלה, אם כי, לעתים קרובות רוצות מקשים שטוחים השטחה היא המתאם בין צורה שהיא טבעית עבור נתונים מובנים לבין צורה שהיא טבעית עבור גיליונות אלקטרוניים, משתני סביבה ומאגרי מפתחות מנוקדים זוהי פעולה קטנה שבפועל בשקט חוסם הרבה משימות מעצבנות אחרת.
מהו משטח JSON?
משטח JSON ממיר אובייקט JSON מקונן לאובייקט ברמה אחת כאשר כל מפתח הוא הנתיב המלא מהשורש לערך עלה. גם תחביר הנתיב אינו שרירותי: RFC 6901 מגדיר JSON Pointer, הדרך הסטנדרטית להתייחס לערך אחד בתוך מסמך.The מקונן {"user":{"name":"Ada","address":{"city":"Austin"}}} הופך להיות השטוח {"user.name":"Ada","user.address.city":"Austin"}. שום דבר בערכים לא משתנה; רק הכתובת שלהם משתנה. כל עלה, עמוק ככל שיהיה, מקבל מפתח אחד שמפרט כיצד להגיע אליו.
מערכים מטופלים באותו אופן, כאשר אינדקס המערך הופך לקטע נתיב: {"roles":["admin","editor"]} משתטח ל {"roles.0":"admin","roles.1":"editor"}. האינדקס במפתח הוא מה שמאפשר לפעולה ההפוכה לבנות מחדש את המערך בסדר הנכון. הפעולה ההפוכה, לא משוטחת, לוקחת אובייקט שטוח של מפתחות מנוקדים ומשחזרת את האובייקטים והמערכים המקוננים, ומחליטה בכל שלב אם קטע נתיב נותן שם למאפיין אובייקט או לאינדקס מערך. כאשר משטחים ולא משוטחים משתמשים באותו סימון מפריד ומערך, הם הפוכים מדויקים, וכי נסיעה הלוך ושוב ללא הפסדים היא התכונה שהופכת את הכלי לאמין לעבודה אמיתית ולא לנוחות חד-כיוונית.
למה שאני אשטח את JSON מלכתחילה?
מכיוון שהרבה מערכות מדברות רק זוגות מפתח-ערך שטוחים, ונתיב מנוקד הוא הדרך הסטנדרטית לשאת דרכם מבנה מקונן מבלי לאבד אותו הדוגמה הברורה ביותר היא גיליון אלקטרוני גיליון אלקטרוני הוא רשת של עמודות, ואין עמודה עבור "העיר בתוך הכתובת בתוך המשתמש." לשטח את האובייקט ו user.address.city הופך לכותרת עמודה אחת שהערך יכול לחיות תחתיה, וזה בדיוק מה שההגדרות שלי-ייצוא כרטיס היה צריך.
אותה צורה מופיעה במקומות רבים אחרים משתני סביבה ו .env קבצים שטוחים, וכלים הממפים את התצורה שלהם משתמשים בנתיבים מנוקדים או מודגשים ספריות בינלאומיות מפתחות את המחרוזות שלהן עם נתיבים מנוקדים כמו checkout.button.label. פלטפורמות דגל תכונה, סכימות אירועי ניתוח והרבה צינורות רישום כולם רוצים רמה אחת של מפתחות, לעתים קרובות כדי שיוכלו לאינדקס או לבצע שאילתות לכל שדה באופן עצמאי. בכל מקרה הקינון הוא אמיתי ומשמעותי, והשטחה משמרת אותו בנתיב במקום להשליך אותו. כאשר הייצוג השטוח שירת את מטרתו, unflatten בונה מחדש את האובייקט המקורי. אם אתה גם עובר בין JSON לגיליונות אלקטרוניים ספציפית, ה ממיר CSV ל-JSON הוא בן לוויה הטבעי לרגל הטבלה של אותו טיול.
כיצד מטפלים במערכים בעת השטחה?
מערכים הם החלק שאנשים טועים לרוב, ולכן כדאי לדייק אלמנט מערך משוטח באמצעות האינדקס המספרי שלו כקטע נתיב, ששומר על הסדר ומאפשר לבנות מחדש את המערך בדיוק הכלי Toolz מציע שני סימונים עבור אותו אינדקס, והם מקודדים את אותו מידע עם תחביר שונה.
| קלט | סימון נקודות | סימון סוגר |
|---|---|---|
{"roles":["admin","editor"]} |
roles.0, roles.1 |
roles[0], roles[1] |
{"items":[{"id":1}]} |
items.0.id |
items[0].id |
{"matrix":[[1,2]]} |
matrix.0.0 |
matrix[0][0] |
כותב סימון נקודות roles.0, שהוא קומפקטי ותואם כמה מערכות config ו-i18n מפתחות את הערכים שלהן. כותב סימון סוגר roles[0], המשקף את תחביר הגישה ל-JavaScript ואת סגנון הנתיב שבו משתמשות שפות שאילתה מסוימות. אף אחד מהם אינו נכון יותר; אתה בוחר את זה שהמערכת בקצה השני מצפה. הדבר החשוב הוא עקביות: לא משנה באיזה סימון אתה משטח, השתמש באותו אחד כדי לבטל את השטחה, כי כך הכלי יודע מקטע מספרי פירושו "array index" במקום " מפתח אובייקט שהוא במקרה מספר." ברירת המחדל של ה-Toolz flattener היא סימון נקודות ומאפשרת לך לעבור לסוגריים בלחיצה אחת.
כיצד אוכל להשתמש במשטח JSON?
לזרימה יש שני כיוונים וכמה אפשרויות. התחל בבחירה שטוח או לא שטוח עם המתג בחלק העליון. Flatten לוקח JSON מקונן ומייצר מפתחות מנוקדים; לא שטוח לוקח מפתחות מנוקדים ובונה מחדש את המבנה המקונן. Load Sample ממלא דוגמה מעובדת עבור כל כיוון שבו אתה נמצא, כך שתוכל לראות את הצורה של הקלט והפלט לפני הדבקת הנתונים שלך.
הדבק את ה-JSON שלך בתיבת הקלט. עבור שטוח, כלומר אובייקט מקונן; עבור לא שטוח, זהו אובייקט שטוח שהמפתחות שלו הם נתיבים מנוקדים. הקלט חייב להיות JSON חוקי, ואם לא, הכלי מדווח על המנתח' הודעת s ומיקום הבעיה במקום למסור לך פלט ריק, כך שפסיק נגרר תועה ממהר למצוא. הגדר את סגנון המפתח: ברירת המחדל של המפריד היא נקודה וניתן לשנות אותו כאשר המפתחות שלך כבר מכילים נקודות, והחלפת סימון המערך עוברת ביניהן roles.0 ו roles[0]. שמור את שתי ההגדרות הללו זהות על פני שטוח וההתאמה שלו לא שטוחה כך שהנסיעה הלוך ושוב תעמוד בשורה. לחץ על כפתור הפעולה, בדוק את ספירת המקשים המאשרת כמה עלים הופקו, והעתק את הפלט או הורד אותו בתור a .json קובץ. כל העניין פועל ברגע שאתה לוחץ, בדפדפן שלך, בלי שום דבר שנשלח לשום מקום.
האם השטחה ללא אובדן, ומהם מקרי הקצה?
לכלי Toolz, כן, עם מקרה קצה אחד שכדאי לדעת. Scalars, null, בוליאנים ומספרים שורדים ללא נגיעה החלק העדין הוא מיכלים ריקים: חפץ ריק {} או מערך ריק [] נשמר כערך עלה ולא נשמט בשקט, כך שקונפיג שמסתמך על רשימה ריקה עדיין מסתובב בדיוק למה שהיה הרבה משטחים תמימים מאבדים מיכלים ריקים, מה שמשנה בשקט את המשמעות של מסמך, אז זו בחירה מכוונת.
המגבלה האמיתית האחת היא מפתחות שכבר מכילים את המפריד. אם לנתונים שלך יש מפתח אובייקט עם נקודה מילולית בתוכו, כמו {"a.b":1}, ואתה משתטח עם מפריד נקודות, הנתיב הופך מעורפל: לא שטוח לא יכול לדעת אם a.b היה מפתח אחד או מקונן a ואז b. התיקון הוא לשנות את המפריד לתו שאינו מופיע במפתחות שלך, כגון קו נטוי או צינור, ולהשתמש באותו מפריד לשני הכיוונים. זה אותו סוג של בעיית בריחה שאתה רואה מתי מפרידי CSV מתנגשים בנתונים, ואותו פתרון חל: בחר מפריד שהערכים שלך אינם מכילים. מחוץ למקרה זה, השטחה ואחריה לא משוטחת עם הגדרות תואמות משחזרת את המסמך המקורי בדיוק, כולל מערכים ומיכלים ריקים.
מה ההבדל בין השטחה לבין המרה לפורמט אחר?
השטחה אינה המרת פורמט; זהו ארגון מחדש בתוך JSON. הפלט של השטחה הוא עדיין JSON, רק עם רמה אחת של מפתחות מנוקדים במקום קינון. זה שונה מהממירים שהופכים את JSON לסידרה שונה באמת, והידיעה איזה מהם אתה צריך חוסכת שלב.
אם אתה רוצה את אותם נתונים המבוטאים כ-YAML עבור קובץ תצורה, ה ממיר JSON ל-YAML האם הכלי, כי זה משנה את התחביר ולא את הצורה אם אתה רוצה ממשק TypeScript המתאר את המבנה כך שהחזית שלך תדע במה הוא מטפל, ה ממיר JSON ל-TypeScript מסיק כי ממדגם. אם אתה רוצה חוזה רשמי לאימות, ה מחולל סכימות JSON גוזר סכימת JSON מדוגמה השטחה יושבת לצד אלה במקום להחליף אותם: אתה משטח כאשר מערכת במורד הזרם רוצה רמה אחת של מפתחות, ואתה ממיר כאשר מערכת רוצה שפה אחרת. לעתים קרובות אני עושה את שניהם ברצף, משטח מטען כדי לערוך אותו כעמודות ולאחר מכן, בנפרד, יוצר סוגים עבור הגרסה המקוננת שאני מוסר ל-React. להדפסה יפה או אימות של ה-JSON בכל נקודה בשרשרת זו, ה פורמט JSON הוא כלי השירות שאני שומר פתוח בכרטיסייה הבאה.
איך unflatten מחליט בין מערך לאובייקט?
זהו המנגנון שגורם לנסיעה הלוך ושוב לעבוד, והבנתו מסבירה הן את הכלי 's ברירות המחדל והן את הקצה החד האחד שלו. כאשר לא שטוח קורא מפתח כמו user.roles.0, זה מפצל אותו למקטעים user, roles, ו 0, ואז הולך אותם מבנה בניין תוך כדי תנועה בכל שלב הוא מסתכל על הקטע הבא כדי להחליט איזה סוג של מיכל ליצור אם הקטע הבא הוא מספר שלם לא שלילי, הוא עושה מערך; אם זה משהו אחר, זה עושה אובייקט. כך roles.0 אומר לכלי ש roles צריך להיות מערך שהאלמנט הראשון שלו הוא הערך, בעוד address.city אומר את זה ש address צריך להיות חפץ עם א city רכוש.
הכלל היחיד הזה, " מקטע שלם פירושו אינדקס מערך," זו הסיבה ש-flatten ו-unflatten עם הגדרות תואמות משחזרים מערכים בדיוק. זו גם הסיבה שסימון המערך שתבחר צריך להיות עקבי. בסימון נקודות אינדקס המערך ומפתח אובייקט הם שניהם רק טקסט בין נקודות, כך שהכלי מסתמך לחלוטין על מבחן המספרים השלמים. בסימון סוגר ה [0] תחביר הופך את הכוונה למפורשת עוד לפני שהפיצול קורה. כל אחד מהם עובד, אבל ערבוב שלהם, השטחה בסוגריים וביטול השטחה עם נקודות, שובר את האות שהכלי תלוי בו.
הנה הקצה החד הנובע מהכלל: אובייקט שהמפתחות שלו הם באמת המיתרים "0", "1", "2" לא ניתן להבחין, לאחר שיטוח, ממערך. שניהם מייצרים את המפתחות 0, 1, 2, ו unflatten יבנה אותם מחדש כמערך כי זה המקרה הנפוץ ביותר. אם אתה באמת צריך אובייקט עם מקשי מחרוזת מספריים כדי לשרוד את הנסיעה הלוך ושוב, זה המצב היחיד שבו השטחה וביטול השטחה לא יחזירו לך את הסוג המדויק, ועדיף לך לשמור על האובייקט הזה מקונן או להשתמש בסכימת מפתח לא מספרי. בשנים של ביצוע זה פגעתי במקרה הזה בדיוק פעמיים, בשתי הפעמים בנתונים שללא ספק עוצבו בצורה שגויה מלכתחילה, כך שברירת המחדל היא הסחר הנכון עבור כמעט כולם. זה אותו סוג של החלטה פרגמטית מאחורי שמירת מספרים עם אפסים מובילים כמו מחרוזות ב- ממיר CSV ל-JSON: הכלי מייעל את המשמעות של הנתונים כמעט תמיד, ומתעד את החריג הנדיר במקום להפוך את הנתיב המשותף למסורבל.
האם JSON שלי בטוח להדביק לתוך הכלי הזה?
כן, וזה ארכיטקטוני ולא הבטחה. Parsing, שיטוח, unflattening, ו serializing כל לרוץ כמו JavaScript בתוך הכרטיסייה דפדפן משלך אין העלאה, אין שרת הלוך ושוב, ושום דבר לא נרשם או מאוחסן פתח את הדפדפן שלך's כרטיסיית רשת ולחץ על כפתור הפעולה: אין בקשה יוצאת ברגע שהדף נטען אתה יכול להתנתק מהאינטרנט וזה ממשיך לעבוד, כי מעולם לא היה שרת בלולאה מלכתחילה.
זה משנה יותר ממה שזה עשוי להיראות, כי JSON מטענים הם בדיוק מסוג הדברים שנושאים סודות: אסימוני API בתצורה, נתונים אישיים בתגובת API, מזהים פנימיים ב-settings blob. a flattener שהעלה את האובייקט שלך לשרת יהפוך מטען פרטי למישהו אחר's log line.עיבוד בצד הלקוח מסיר את הסיכון לחלוטין, וזו הסיבה שזו ברירת המחדל בכל כלי ב-Toolz.dev. אם אתה רוצה את ההיגיון המלא, פרסתי אותו ב- מדריך פרטיות נתונים לכלים מקוונים, והערכה הרחבה יותר שבה אני משתמש לעבודה מסוג זה נמצאת אצלי מדריך ערכת כלים למפתחי אינטרנט.
שאלות נפוצות
מה זה אומר לשטח את JSON?
שיטוח JSON ממיר אובייקט מקונן לאובייקט ברמה אחת שהמפתחות שלו הם הנתיב לכל ערך. המקונן {"user":{"city":"Austin"}} הופך להיות השטוח {"user.city":"Austin"}. כל ערך עלה מקבל מפתח מנוקד אחד, ולא נשאר קינון בפלט. Unflatten הופך את התהליך ובונה מחדש את המבנה המקונן.
כיצד מטפלים במערכים בעת השטחה?
רכיבי מערך משוטחים באמצעות האינדקס שלהם כקטע נתיב. {"roles":["admin","editor"]} הופך {"roles.0":"admin","roles.1":"editor"} בסימון נקודה, או {"roles[0]":"admin","roles[1]":"editor"} בסימון סוגריים האינדקס שומר על הסדר כך שניתן לבנות מחדש את המערך בדיוק כאשר אתה מבטל את השטיח.
האם אני יכול לבטל מפתחות מנוקדים בחזרה ל-JSON מקונן? כן. עבור למצב לא משוטח והדבק אובייקט שטוח שהמפתחות שלו הם נתיבים מנוקדים הכלי בונה מחדש את האובייקטים והמערכים המקוננים, ומחליט מערך מול אובייקט לפי האם כל קטע נתיב הוא אינדקס שלם. שטוח ולא משוטח הם הפוכים מדויקים כאשר סימון המפריד והמערך תואמים.
מה ההבדל בין סימון מערך נקודות וסוגריים?
שניהם מקודדים את אותו אינדקס מערך; רק התחביר שונה. סימון נקודה כותב items.0.id, שהוא קומפקטי ונפוץ במפתחות config ו-i18n. כותב סימון סוגר items[0].id, התואם לתחביר גישה ל-JavaScript ולכמה שפות שאילתות. בחר את מה שמערכת היעד שלך מצפה, והשתמש באותו אחד עבור שני הכיוונים.
האם השטחה מאבדת נתונים כלשהם? מס 'סקלרים, nulls, בוליאנים, ואפילו אובייקטים ריקים ומערכים ריקים נשמרים כערכי עלה, כך unflattening התוצאה משחזרת את המסמך המקורי הדבר היחיד שיש לצפות בו הוא מפתחות שכבר מכילים את המפריד שלך, וזו הסיבה המפריד ניתן להגדרה.
למה שאשטוח את JSON? השטחה מתאימה נתונים מקוננים למערכות המצפות לרמה אחת של מפתחות: עמודות גיליון אלקטרוני, משתני סביבה, מפתחות תרגום מנוקדים, מאגרי דגל תכונה וצינורות ניתוח ורישום רבים. הנתיב המנוקד נושא את המבנה המקורי בפורמט שטוח כך ששום דבר לא הולך לאיבוד.
מה קורה אם מפתח כבר מכיל נקודה? נקודה מילולית בתוך מפתח אינה חד משמעית עם מפריד הנתיבים, כך שהנסיעה הלוך ושוב יכולה לפצל אותו במקום הלא נכון שנה את המפריד לתו שאינו מופיע במפתחות שלך, כגון קו נטוי או צינור, והשתמש באותו מפריד גם לשטח וגם לא שטוח.
האם ה-JSON שלי מועלה במקום כלשהו? מס 'ניתוח וטרנספורמציה לרוץ כמו JavaScript בדפדפן שלך שום דבר לא מועבר, נרשם, או מאוחסן אתה יכול לאשר זאת על ידי צפייה בכרטיסייה הרשת בזמן השטחה, או על ידי הולך במצב לא מקוון, מאז הכלי ממשיך לעבוד ללא חיבור.



