בפעם הראשונה שכתבתי ביטוי JSONPath שחשוב, טעיתי שלוש פעמים לפני שהוא עבד, וידעתי שהוא שגוי רק בגלל ששער ה-API שהגדרתי החזיר מדיניות ריקה במקום השדה שרציתי. לא הייתה לולאת משוב. הייתי עורך את הביטוי, פורס מחדש ומחכה. ברגע שהתחלתי לשמור בודק JSONPath פתוח בלשונית אחרת, אותה עבודה ארכה שתי דקות במקום אחר הצהריים. המדריך הזה עוסק באופן שבו אני משתמש ב בודק JSONPath על Toolz.dev, מה בעצם עושה התחביר, והמלכודות הקטנות שגורמות לביטוי לא מחזירות דבר כשהיית בטוח שהוא צריך להתאים.
TL;DR: JSONPath היא שפת שאילתה עבור JSON, הדרך שבה XPath מיועד ל-XML. בודק JSONPath מעריך ביטוי כמו
$.store.book[*].authorכנגד מסמך ומחזירה כל ערך תואם בתוספת הנתיב שלו.The בודק JSONPath עושה זאת לחלוטין בדפדפן שלך, עם תמיכה בתווים כלליים, ירידה רקורסיבית, פרוסות, איגודים וביטויי סינון, כך שתוכל לבנות ולאפות באגים בשאילתה מול נתונים אמיתיים לפני שתדביק אותה בקוד.
מהו JSONPath?
JSONPath הוא תחביר קומפקטי לבחירת חלקים ממסמך JSON אתה כותב נתיב קצר שמתאר מסלול דרך הנתונים, והערכתו מחזירה את הערך או הערכים באותו מסלול הרעיון מגיע מ Stefan Goessner's הצעה משנת 2007, ששיקף בכוונה את XPath כך שכל מי ששאל XML ירגיש בבית. במשך שנים לא היה מפרט רשמי, רק המאמר הזה ומשפחת יישומים שהסכימו בעיקר, ובתחילת 2024 פרסם ה-IETF RFC 9535 כדי להצמיד את הדקדוק למטה.
אתה פוגש את JSONPath לעתים קרובות יותר ממה שאתה יכול לצפות. זוהי שפת הבורר בכלי בדיקת API כמו Postman ו-Karate, ב-Kubernetes kubectl עיצוב פלט, בפונקציות AWS CloudWatch ו-Step, במעבדי יומן, ובעשרות פלטפורמות בעלות קוד נמוך שבהן משתמש צריך לשלוף שדה אחד ממטען webhook מבלי לכתוב קוד. לימוד זה פעם אחת מחזיר את כל אלה.
המודל המנטלי פשוט מסמך JSON הוא עץ אובייקטים שמו ענפים, מערכים ממוספרים ענפים, והעלים הם הערכים הסקלרים שלך ביטוי JSONPath הוא קבוצה של כיוונים להליכה על העץ הזה, והתוצאה היא כל עלה או תת-עץ שאתה נוחת עליו איפה שהוא מקבל עוצמה זה שביטוי יחיד יכול לנחות על הרבה מקומות בבת אחת.
מה עושה בודק JSONPath בעצם?
בודק לוקח שתי כניסות, JSON שלך וביטוי, ומראה לך כל צומת שהביטוי בוחר זה נשמע ברור, אבל הערך נמצא במשוב כאשר ביטוי לא מחזיר כלום, או מחזיר יותר ממה שציפית, בודק הופך משחק ניחושים לבדיקה של שתי שניות, כי אתה יכול לראות בדיוק אילו צמתים התאימו ולהתאים תו אחד בכל פעם.
על Toolz.dev הזרימה קצרה הדבק מסמך JSON, או טען את חנות הספרים לדוגמה שרוב מדריכי JSONPath משתמשים בה, הקלד ביטוי והעריך הכלי מפרט כל ערך מותאם עם ספירה פועלת, ותוכל להחליף את הפלט בין שלוש תצוגות ערכים נותנים לך רק את התוצאות כמערך JSON נתיבים נותנים לך את המיקום המנורמל של כל התאמה, וזו הדרך המהירה ביותר לגלות את הביטוי שאתה צריך בפועל ערכים נותנים לך את שניהם יחד, כך שתוכל לראות את הנתיב ואת הערך זה לצד זה.
הסיבה לבדוק מול נתונים אמיתיים ולא סיבה לגבי זה בראש שלך היא שJSON מהטבע מבולגן יותר מהדוגמאות שדה הוא לפעמים אובייקט ולפעמים מערך מפתח שציפית לו חסר בחצי הרשומות מספר הגיע כמחרוזת הפעלת הביטוי כנגד משטחי המטען בפועל ההפתעות האלה מיד במקום בזמן הפריסה.
כיצד אוכל לבחור פריטים ממערך?
מערכים הם המקום שבו מתרחשת רוב עבודת JSONPath, ויש ארבע דרכים לטפל בהם.
אינדקס בודד בוחר אלמנט אחד. $.store.book[0] מחזירה את הספר הראשון, ו-JSONPath, כמו רוב השפות, נחשב מאפס. אינדקס שלילי נחשב מהסוף, אז $.store.book[-1] מחזירה את הספר האחרון מבלי שתצטרך לדעת כמה יש. הצורה השלילית הזו שימושית באמת כאשר אתה רוצה את הפריט העדכני ביותר ביומן או את הערך האחרון בעדכון.
תו כללי בוחר כל אלמנט. $.store.book[*] מחזיר את כל ארבעת הספרים, ו $.store.book[*].author מחזיר את המחבר של כל אחד, נותן לך מערך נקי של מחברים. התו הכללי עובד גם על אובייקטים, שם $.store.* מחזירה כל ערך של אובייקט החנות ללא קשר למפתח.
איגוד בוחר קבוצה מסוימת. $.store.book[0,2] מחזירה את הספר הראשון והשלישי, ואותו תחביר פסיק עובד עם שמות, אז $['store']['bicycle'] ומקשים מצוטטים בסוגריים מאפשרים לך להתייחס למקשים המכילים רווחים או סימני פיסוק שצורת הנקודה אינה יכולה.
פרוסה בוחרת טווח, בהשאלה Python's start:end:step טופס. $.store.book[:2] לוקח את שני הראשונים, $.store.book[1:3] לוקח טווח ביניים עם אינדקס הקצה בלעדי, $.store.book[::2] לוקח כל אלמנט שני, ו $.store.book[::-1] הופך את המערך פרוסות הן החלק הכי פחות מוכר בתחביר וזה ששומר הכי הרבה הקלדה ברגע שיש לך את זה.
מה עושה הנקודה הכפולה?
הנקודה הכפולה היא ירידה רקורסיבית, והתכונה היא שגורמת ל-JSONPath להרגיש כמו חיפוש ולא נתיב. $..author מוצא כל author מפתח בכל מקום במסמך, לא משנה כמה עמוק הוא מקונן, ו $..* מחזירה כל ערך בכל רמה כאשר אינך יודע את הצורה המדויקת של מסמך, או כאשר אותו שדה מופיע בכמה עומקים, ירידה רקורסיבית מוצאת את כולם בביטוי אחד.
שקול את חנות הספרים לדוגמה. $..price מחזירה חמישה ערכים, ארבעת מחירי הספרים ומחיר האופניים, כי הוא יורד לכל חפץ ואוסף כל price זה מוצא. a plain $.store.book[*].price היה מחזיר רק את ארבעת מחירי הספרים, כי הוא הולך במסלול קבוע ההבדל בין שני הביטויים האלה הוא ההבדל בין לבקש מחירים במיקום ידוע לבין לבקש מחירים בכל מקום.
ירידה רקורסיבית מספיק חזקה כדי להיות מסוכנת, במובן שהיא יכולה להתאים ליותר ממה שהתכוונת בדיוק בגלל זה בוחן חשוב כאן רוץ $..name נגד מטען לא מוכר ואתה עלול לגלות שהוא תואם לשם משתמש, שם מוצר ושם קובץ שלא היה לך מושג ששיתף מפתח. לראות את הנתיבים בפלט אומר לך אם לצמצם את הביטוי לפני שאתה מסתמך עליו.
כיצד פועלים ביטויי סינון?
מסנן שומר רק את האלמנטים שעבורם תנאי נכון, והוא כתוב [?(...)] עם @ עומד לאלמנט הנוכחי. $.store.book[?(@.price < 10)] מחזירה את הספרים בזול מעשרה בתוך הפילטר ניתן להשוות שדה מול מילולי עם המפעילים ==, !=, <, <=, >, ו >=, בדוק את עצם הנוכחות של שדה, ושלב תנאים עם && ו ||.
כמה דוגמאות קונקרטיות מבהירות את הצורה:
$.store.book[?(@.category == "fiction")]בוחר את הכותרות הבדיוניות.$.store.book[?(@.price < 10 && @.category == "fiction")]מצטמצם לסיפורת זולה.$.store.book[?(@.isbn)]בוחר רק את הספרים שיש להם ISBN, תוך שימוש בקיום ולא בהשוואה.$.vals[?(@ > 2)]מסנן מערך רגיל של מספרים, שבו@בפני עצמו מתייחס ליסוד עצמו.
באג הסינון הנפוץ ביותר הוא אי התאמה מסוג. ב-JSON, "12" ו 12 האם ערכים שונים, כך מסנן שמשווה שדה מספרי למספר מצוטט, או שדה מחרוזת למספר חשוף, לא תואם בשקט כלום כאשר מסנן מפתיע אותך, הדבר הראשון שיש לבדוק הוא האם השדה והמילולית הם אותו סוג בדיקת הביטוי מול הנתונים האמיתיים, שבו אתה יכול לראות את הערכים בפועל, היא איך אתה תופס את זה בשניות במקום לאחר פריסה כושלת.
JSONPath לעומת JSON Pointer לעומת הבדל JSON
שלושת הכלים האלה נוגעים כולם במבנה JSON, אבל הם עונים על שאלות שונות, ובחירת הכלים הלא נכונים מבזבזת זמן. הנה איך הם משווים:
| גישה | תשובות | התאמות | הטוב ביותר עבור |
|---|---|---|---|
| JSONPath | אילו צמתים מספקים את השאילתה הזו? | אפס, אחד, או רבים | חילוץ שדות, סינון מערכים, חקר צורות לא ידועות |
| מצביע JSON (RFC 6901) | מה יש במיקום הזה בדיוק? | תמיד בדיוק אחד | התייחסות לשדה קבוע יחיד, כמו ב-JSON Schema $ref |
| JSON diff | מה השתנה בין שני מסמכים? | סט של שינויים | השוואת שתי גרסאות של אותם נתונים |
JSON Pointer, מוגדר ב RFC 6901, פונה למקום אחד מדויק עם נתיב מופרד כמו /store/book/0/title, והוא אף פעם לא משתמש בתווים כלליים או במסננים. להגיע אליו כאשר אתה צריך לתת שם לשדה בודד באופן חד משמעי. להגיע עבור JSONPath כאשר ביטוי בודד צריך לבחור קבוצה של שדות. וכאשר השאלה האמיתית שלך היא מה שונה בין שני מטענים ולא מה שאילתה בוחרת, א JSON Diff הוא הכלי הנכון לדעת מי מהשלושה שאתה צריך בעצם זה חצי מהקרב.
למה הביטוי שלי לא מחזיר תוצאות?
תוצאה ריקה כמעט תמיד מגיעה מאחת מקומץ סיבות, ובוחן מאפשר לך לשלול אותן במהירות.
הראשון הוא אי התאמה מבנית כתבת $.data.items.name כאשר items הוא מערך, אז היית צריך $.data.items[*].name עם תו כללי צורת הנקודה נכנסת לאובייקט, ומערך אינו אובייקט עם a name מפתח, אז הנתיב מסתיים ללא מוצא. החלפת תצוגת הפלט לנתיבים ודריכה של הביטוי קטע אחד בכל פעם מראה לך בדיוק היכן הוא מפסיק להתאים.
השני הוא שגיאת כתיב או מעטפת. מפתחות JSON הם רגישים לאותיות גדולות, אז $.userId לא יתאים ל userID שדה, ורווח נגרר או שגיאת הקלדה בשם מפתח מייצרים את אותו שום דבר שקט. מכיוון שהבודק מראה לך את המסמך ממש ליד הביטוי, הם מהירים לזיהוי.
השלישי, כפי שכוסה לעיל, הוא אי התאמה מסוג מסנן, כאשר השוואה מספרית פועלת מול ערך מחרוזת או הפוך. הרביעי הוא בהנחה שקיים מפתח בכל אלמנט כאשר הוא קיים רק בחלק מסנני ירידה רקורסיבית וקיום הם התרופות הרגילות. בכל מקרה, התיקון נובע מצפייה באילו צמתים הביטוי נוגע, ובדיוק בשביל זה נועד בודק.
אם אתה בונה על פני המחסנית כמו שאני עושה, עובר בין API של Laravel, קצה קדמי של React וסקריפט מעטפת מדי פעם, JSONPath מופיע בשלושתם, ובוחן מבוסס דפדפן שלעולם לא מעלה את הנתונים שלך הוא הכלי שאני לשמור על הקרוב ביותר כתבתי על איך כלי עזר כמו זה משתלבים בערכה רחבה יותר ב ערכת כלים למפתחי אינטרנט, והמקרה לשמירה על סוג זה של עבודה בצד הלקוח הוא ב פרטיות נתונים בכלים מקוונים מדריך.
איך זה מתאים לשאר זרימת העבודה של JSON שלי?
בודק JSONPath הוא לעתים רחוקות הכלי היחיד הפתוח. כאשר ה-JSON שאני שואל הגיע ממוזער או עם הזחה לא עקבית, אני מריץ אותו דרך פורמט JSON ראשית כדי שאוכל לקרוא את המבנה בזמן שאני כותב את הביטוי המעצב והבוחן ביחד הם איך אני עובר מתגובת API בלתי קריא לשאילתה עובדת.
ברגע שאני יודע אילו שדות אכפת לי, השלב הבא הוא לעתים קרובות לעצב אותם מחדש אם אני צריך להזין את הערכים שנבחרו לגיליון אלקטרוני או לקובץ סביבה, ה JSON Flattener הופך את המבנה המקונן למקשי סימון נקודות, ותחביר הנתיב שלו קרוב מספיק ל-JSONPath כדי שהשניים יחזקו זה את זה. אם אני בונה סוג לנתונים ב-TypeScript, ה json ל-Typescript ממיר יוצר את הממשק, ואם אני צריך לאמת את הצורה במקום רק לקרוא אותה, ה מחולל סכמת JSON מייצר סכימה שאני יכול להוסיף לה אילוצים. JSONPath הוא שלב החקירה; הכלים האלה הם מה שאני עושה עם מה שאני מוצא.
נקודת הפרטיות שווה לחזור כי JSONPath עבודה כל כך הרבה פעמים קורה נגד נתונים רגישים תגובות API לשאת אסימונים, רשומות משתמש, ומזהים פנימיים, והדבקתם לתוך כלי בצד השרת אומר לסמוך על מישהו אחר & #39;s יומני.V. כי בודק Toolz.dev מנתח ומעריך לחלוטין בדפדפן שלך, שום דבר מזה לא עוזב את המכונה שלך, והכלי ממשיך לעבוד עם הרשת מנותקת זה ההבדל בין כלי אתה יכול להשתמש על מטען בימוי ואחד אתה יכול להשתמש על הדבר האמיתי.
שאלות נפוצות
למה משמש JSONPath?
JSONPath משמש לבחירה וחילוץ של חלקים ממסמך JSON עם ביטוי יחיד. זוהי שפת השאילתה בכלי בדיקת API, עיצוב פלט Kubernetes, שירותי ענן כמו AWS Step Functions ופלטפורמות רבות עם קוד נמוך, בכל מקום שמישהו צריך למשוך שדה או לסנן מערך מתוך מטען JSON מבלי לכתוב קוד פרוצדורלי.
כיצד אוכל לבחור כל רכיב של מערך ב-JSONPath?
השתמש בכרטיס הכללי, אז $.items[*] מחזירה כל רכיב במערך הפריטים ו $.items[*].id מחזירה את המזהה של כל אחד מהם. אתה יכול גם לבחור אלמנט אחד לפי אינדקס עם $.items[0], האלמנט האחרון עם המדד השלילי $.items[-1], סט עם איחוד כמו $.items[0,2], או טווח עם פרוסה כמו $.items[1:3].
מה המשמעות של הנקודה הכפולה ב-JSONPath?
הנקודה הכפולה היא ירידה רקורסיבית, המחפשת בכל עומק. $..author מוצא כל מפתח מחבר בכל מקום במסמך, לא משנה כמה עמוק מקונן, ו $..* מחזירה כל ערך בכל רמה זוהי הדרך המהירה ביותר לשלוף שדה מתוך מסמך שאת המבנה המדויק שלו לא מכירים מראש.
כיצד פועלים ביטויי סינון ב-JSONPath?
מסנן [?(...)] שומר רק את האלמנטים שעבורם תנאי נכון, עם @ התייחסות לאלמנט הנוכחי. לדוגמה $.book[?(@.price < 10)] מחזירה ספרים בזול מעשרה, ואפשר לשלב תנאים עם && ו ||, כגון [?(@.price < 10 && @.category == "fiction")]. אתה יכול גם לבדוק עבור שדה 's קיום עם [?(@.isbn)].
מדוע הביטוי שלי JSONPath לא מחזיר כלום?
שתי הסיבות הנפוצות ביותר הן אי התאמה מבנית ואי התאמה מסוג בדוק שכל מפתח קיים ומאוית עם המעטפת המדויקת, ושהשתמשת בכרטיס כללי שבו הנתונים הם מערך ולא אובייקט. במסננים, זכור כי "12" ו-12 הם ערכים שונים, אז השווה שדה מחרוזת לערך מצוטט ושדה מספרי למספר חשוף.
מה ההבדל בין JSONPath ל-JSON Pointer?
מצביע JSON פונה למיקום מדויק אחד, כמו /store/book/0/title, ותמיד מחזיר ערך בודד. JSONPath היא שפת שאילתה שבה ביטוי בודד יכול להתאים לצמתים רבים בו-זמנית באמצעות תווים כלליים, ירידה רקורסיבית ומסננים. השתמש במצביע כדי להפנות לשדה קבוע אחד, וב-JSONPath כדי לבחור קבוצה של שדות או לסנן אוסף.
האם אני יכול לראות את הנתיב של כל התאמה, לא רק את הערך?
כן. החלף את מצב הפלט לנתיבים כדי לקבל את המיקום המנורמל של כל התאמה, או ערכים כדי לקבל את הנתיב והערך ביחד. לראות את הנתיבים האמיתיים היא הדרך המהירה ביותר לחדד ביטוי עד שהוא בוחר בדיוק את הצמתים שהתכוונת, מה שמועיל במיוחד בירידה רקורסיבית.
האם ה-JSON שלי מועלה כשאני משתמש בבוחן?
מס 'המסמך מנותח והביטוי מוערך בדפדפן שלך עם JavaScript, כך ששום דבר לא מועבר, נרשם או מאוחסן אתה יכול לאשר את זה על ידי צפייה בכרטיסייה הרשת בזמן שאתה מפעיל שאילתה, או על ידי ניתוק מהאינטרנט, כי הבוחן ממשיך לעבוד במצב לא מקוון לאחר שהדף נטען.
נסה את זה על הנתונים שלך עם החינם בודק JSONPath. הוא מעריך תווים כלליים, ירידה רקורסיבית, פרוסות, איגודים וביטויי סינון לחלוטין בדפדפן שלך, ללא שום דבר שהועלה.



