{"id":15655123,"url":"https://github.com/zordius/json-path-processor","last_synced_at":"2025-05-01T14:54:07.836Z","repository":{"id":15396975,"uuid":"18128813","full_name":"zordius/json-path-processor","owner":"zordius","description":"JsonPathProcessor (JPP) - A common data processor target to process data without running try catch hell, and get/set properties of nested objects.","archived":false,"fork":false,"pushed_at":"2017-09-21T02:22:45.000Z","size":1115,"stargazers_count":26,"open_issues_count":2,"forks_count":10,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-01T14:54:01.868Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.npmjs.org/package/json-path-processor","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zordius.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.txt","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-26T06:25:38.000Z","updated_at":"2025-01-20T15:23:58.000Z","dependencies_parsed_at":"2022-08-25T18:30:16.151Z","dependency_job_id":null,"html_url":"https://github.com/zordius/json-path-processor","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zordius%2Fjson-path-processor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zordius%2Fjson-path-processor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zordius%2Fjson-path-processor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zordius%2Fjson-path-processor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zordius","download_url":"https://codeload.github.com/zordius/json-path-processor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251895424,"owners_count":21661342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T12:56:25.679Z","updated_at":"2025-05-01T14:54:07.820Z","avatar_url":"https://github.com/zordius.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"json-path-processor\n===================\n\nJsonPathProcessor (JPP) - A common data processor target to process data without running try catch hell, and get/set properties of nested objects.\n\n[![npm version](https://img.shields.io/npm/v/json-path-processor.svg)](https://www.npmjs.org/package/json-path-processor) [![npm download](https://img.shields.io/npm/dm/json-path-processor.svg)](https://www.npmjs.org/package/json-path-processor) [![Dependency Status](https://david-dm.org/zordius/json-path-processor.svg)](https://david-dm.org/zordius/json-path-processor) [![Build Status](https://travis-ci.org/zordius/json-path-processor.svg?branch=master)](https://travis-ci.org/zordius/json-path-processor) [![Test Coverage](https://codeclimate.com/github/zordius/json-path-processor/badges/coverage.svg)](https://codeclimate.com/github/zordius/json-path-processor) [![Code Climate](https://codeclimate.com/github/zordius/json-path-processor/badges/gpa.svg)](https://codeclimate.com/github/zordius/json-path-processor) [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE.txt)\n\n[![Sauce Test Status](badge.png)](https://saucelabs.com/u/zordius_jpp)\n\nInstallation\n------------\n\n```sh\nnpm install json-path-processor\n```\n\nIn browser:\n```html\n\u003cscript src=\"dist/jpp.js\"\u003e\u003c/script\u003e\n```\n\nIn an AMD loader:\n```javascript\nrequire('jpp', function (jpp) {/*....*/});\n```\n\nIn nodejs:\n```javascript\nvar jpp =  require('json-path-processor');\n```\n\nFeatures\n--------\n\n* Chainning\n* Iterate objects by simplified JSONPath\n   * similar packages: \u003ca href=\"https://www.npmjs.org/package/dotty\"\u003edotty\u003c/a\u003e , \u003ca href=\"https://www.npmjs.org/package/dot-access\"\u003edot-access\u003c/a\u003e , \u003ca href=\"https://www.npmjs.org/package/deep-get-set\"\u003edeep-get-set\u003c/a\u003e , \u003ca href=\"https://www.npmjs.org/package/traverse\"\u003etraverse\u003c/a\u003e, \u003ca href=\"https://www.npmjs.org/package/lodash-deep\"\u003elodash-deep\u003c/a\u003e\n* Catch all throwed error automatically\n\nUpgrade Notice\n--------------\n\n* Now JPP stop using lodash and move to ES5. For none ES5 browsers/enviromnent, **you should use polyfills** to ensure JPP works well. You can try \u003ca href=\"http://polyfill.io\"\u003epolyfill.io\u003c/a\u003e or \u003ca href=\"http://polyfills.io/\"\u003epolyfills.io\u003c/a\u003e.\n\n* Some lodash like method behavior changed, please refer to document.\n\nUsage\n-----\n\n```javascript\nvar jpp = require('json-path-processor');\n\n// I wanna update all product title\ndata = jpp(data).each('product.title', function (V) {\n    return something(V);\n}).value();\n\n// Ya, handle all product title and promotion description\n// almost all jpp methods are chainable\ndata = jpp(data).each('extra.promotion', function (O) {\n    O.description = someValue;\n    return O;\n}).each('product.title', someUtilFunc).value();\n\n// jpp play on the object reference so you even do not need to assign back!\njpp(data).each('product', assignProductDefault);\njpp(data).each('product', changeProductDetail);\noutput(data);\n\n// chaining is cool, right?\njpp(data)\n.each('product', playTheProduct)\n.each('product.title', fixProductTitle);\noutput(data);\n```\n\nAPI document and example\n------------------------\n\n* **jpp(data)** : create the JPP chainning object by data.\n\n```javascript\nvar J = jpp(['any', 'data', {or: {recursive: {'object'}}}]);\n```\n\n* **jpp(data, path)** : a shortcut of jpp(data).value(path)\n\n```javascript\nconsole.log(jpp({a: {b: 'OK'}}, 'a.b')); // will get 'OK'\nconsole.log(jpp({a: {b: 'OK'}}, 'a.c.d')); // will get undefined\n```\n\n* **.value(path)** : get value by JSON path. This method can not be chainned. When path is undefined or '' or '$', get whole data.\n\n```javascript\nconsole.log(jpp([1, 3, 5]).value()); // will get [1, 3, 5]\nconsole.log(jpp({a: {b: 'OK'}}).value('a.b')); // will get 'OK'\nconsole.log(jpp({a: {b: 'OK'}}).value('a.c.d')); // will get undefined\n```\n\n* **.get(path)** : get new JPP object by JSON path. All chainned methods on this is different from root object.\n\n```javascript\nconsole.log(jpp({a: {b: 'OK'}}).get('a').get('b').value()); // will get 'OK'\n```\n\n* **.set(path, value, create)** : set new value by JSON path. When value is a function, execute the function with first argument as old value. the return value of the callback function will be assigned. When create exists, create new object by the JSON path, and create will be used as default value to be assigned when the callback function throws exception.\n\n```javascript\n// will get {a: {b: 'OK', c:[1, 3]}}\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).set('a.c.1', 3).value());\n\n// will get {a: {b: 'BAD', c:[1, 4]}}\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).set('a.b', 'BAD').value());\n\n// will get {a: {b: 'OK', c:[1, 4]}}\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).set('a.b.c.d', 'OK?').value());\n\n// set failed ... WE CAN NOT CONVERT ARRAY TO OBJECT\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).set('a.b.c.d', 'OK?', true).value());\n\n// a.b.c[2 ~ 9] will become undefined ... ARRAY SIZE AUTO EXPEND IN JAVASCRIPT\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).set('a.c.10', 'OK?', true).value());\n```\n\n* **.copy(from, to, skip)** : copy value from one JSON path to another. When the JSON path not found, new object will be created. To prevent new object creation, pass skip as true as 3rd param.\n\n```javascript\n// will get {a: {b: 'OK', c:[1, 4], d: 4}}\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).copy('a.c.1', 'a.d').value());\n```\n\n* **.del(path)** : delete a key by JSON path. When the path exists, last key will be deleted; when it do not exist, do nothing.\n\n```javascript\n// will get {a: {b: 'OK', c: [1, 4]}}\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).del('a.b.c').value());\n\n// will get {a: {b: {}}\nconsole.log(jpp({a: {b: {c: {d: 2, q: 1}}}}).del('a.b.c').value());\n```\n\n* **.move(from, to)** : move values from a path to another. when the origin path not found, do nothing.\n\n```javascript\n// will get {a: {b: 'OK', d: [1, 4]}}\nconsole.log(jpp({a: {b: 'OK', c: [1, 4]}}).move('a.c', 'a.d').value());\n```\n\n* **.range(path, args...)** : Works like `lodash.range()` , create range and set the array into the path.\n\n```javascript\n// will get {a: {b: 1, c: [0, 1, 2]}}\nconsole.log(jpp({a: {b: 1}}}).range('a.c', 3).value());\n\n// will get {a: {b: 1, c: [3, 4]}}\nconsole.log(jpp({a: {b: 1}}}).range('a.c', 3, 5).value());\n\n// will get {a: {b: 1, c: [2, 5, 8, 11]}}\nconsole.log(jpp({a: {b: 1}}}).range('a.c', 2, 12, 3).value());\n```\n\n\n* **.find(path, args...)** : Works like `lodash.find()` , return the value. This method can not be chainned.\n\n```javascript\n// will get 3\nconsole.log(jpp({a: {b: [0, 3, 4]}}}).find('a.b', function (O) {return O%2 \u003e 0}));\n```\n\n* **.findLast(path, args...)** : Works like `lodash.findLast()` , return the value. This method can not be chainned.\n\n```javascript\n// will get 5\nconsole.log(jpp({a: {b: [1, 3, 4, 5]}}}).find('a.b', function (O) {return O%2 \u003e 0}));\n```\n\n* **.each(path, function (value, key) {...})** : Works like Array.map(), the callback arguments are: value, index. The return value of callback will be assigned back to JPP object. You can apply second callback function for fallback when the path is not found or not array. When your callback return undefined or throws, the item in array will not be changed.\n\n```javascript\nconsole.log(jpp({a: {b: [1, 3, 5]}}).each('a.b', function (V) {\n    return V * 2;\n}).value());  // will get {a: {b: [2, 6, 10]}}\n\nconsole.log(jpp({a: {b: [1, 3, 5]}}).each('a.b', function (V, I) { // I as index\n    return V * I;\n}).value());  // will get {a: {b: [0 , 3, 10]}}\n\n// fallback when a.c is not array or not object or not found\nconsole.log(jpp({a: {b: [1, 3, 5]}}).each('a.c', function (V) {\n    return V * I;\n}, function (O) {\n    return 'ERROR'\n}).value());  // will get {a: {b: [1 , 3, 5], c: 'ERROR'}}\n```\n\n* **.forIn(path, function (value, key) {...})** : Works like for (I in O), the callback arguments are: value, key. The return value of callback will be assigned back to JPP object. You can apply second callback function for fallback when the path is not found or not object. When your callback return undefined or throws, the item in object will not be changed.\n\n```javascript\n// will get {a: 'OK!', b: 'BAD!', length: '9!'} \n// forIn() will not think object with length property as array.\nconsole.log(jpp({a: 'OK', b: 'BAD', length: 9}).forIn('$', function (V, I) {\n    return V + '!';\n}).value()); \n\n// fallback when a.c is not array or not object or not found\nconsole.log(jpp({a: {b: [1, 3, 5]}}).forIn('a.c', function (V) {\n    return V * I;\n}, function (O) {\n    return 'ERROR'\n}).value());  // will get {a: {b: [1, 3, 5], c: 'ERROR'}}\n```\n\n* **.filter(path, function (value, key) {...})** : Works like Array.filter() but also works well on object. the callback are: value, index|key. The filtered result will be assigned back to JPP object.\n\n```javascript\n// will get {a: {b: {c: [3, 5], d:5}}}\nconsole.log(jpp({a: {b: {c: [2, 3, 4, 5], d: 5}}}).filter('a.b.c', function (V) {\n    return V % 2 \u003e 0;\n}).value()); \n```\n\n* **.concat(path, path, path ...)** : search for all values by proviced JSON path, then concat all arraies into one. None array value will be skipped. When array size \u003e= 1, assign the concated array back to first path. Or, do nothing.\n\n```javascript\n// will get {a: {b: {c: [1, 3], d:5}, d: [1, 3, 1,3]}}\nconsole.log(jpp({a: {b: {c: [1, 3], d: 5}}}).concat('a.d', 'a.b.c', 'a.b.c').value());\n```\n\nSupported JSON Path\n-------------------\n\nWe only support absolute JSON Path and receive only one item.\n\n* $ : refer to self\n* $.foo.bar or .foo.bar or foo.bar or foo['bar'] or ['foo']['bar'] : refer to `foo` then `bar`\n* $.foo.3.bar or foo.3.bar or foo['3'].bar or foo['3']['bar'] : refer to `foo` then 4th item then `bar`\n\nWhen you need to deal with `.` inside your property name, you can just use the array syntax:\n\n```javascript\n// var result = data.sites['google.com'].pageRank.score;\n// prevent exception by jpp way:\nvar result = jpp(data).value(\"sites['google.com'].pageRank.score\");\n```\n\n**TODO** handle `\\` escape inside the array syntax\n\nThe long story\n--------------\n\nAll our life is to handle data....with a loop. Let's start from a basic loop:\n\n```javascript\nfor (I in data) {\n    data[I] = something(data[I]);\n}\n```\n\nTo make jslint happy or ensure the loop correct, we should add property check:\n\n```javascript\nfor (I in data) {\n    if (data.hasOwnProperty(I)) {\n        data[I] = something(data[I]);\n    }\n}\n```\n\nIn real life, data is not always ready. We must handle none data case:\n\n```javascript\nif (data \u0026\u0026 is_object(data)) {\n    for (I in data) {\n        if (data.hasOwnProperty(I)) {\n            data[I] = something(data[I]);\n        }\n    }\n}\n```\n\nFurthermore, please catch something() because they may throw some error.\n\n```javascript\nif (data \u0026\u0026 is_object(data)) {\n    for (I in data) {\n        if (data.hasOwnProperty(I)) {\n            try {\n                data[I] = something(data[I]);\n            } catch (E) {\n                handle_error(E);\n            }\n        }\n    }\n}\n```\n\nThe more assign in the loop, the more try/catch you need.\n\n```javascript\nif (data \u0026\u0026 is_object(data)) {\n    for (I in data) {\n        if (data.hasOwnProperty(I)) {\n            try {\n                data[I].title = something(data[I].title);\n            } catch (E) {\n                handle_error(E);\n            }\n            try {\n                data[I].desciption = something(data[I].description);\n            } catch (E) {\n                handle_error(E);\n            }\n            try {\n                data[I].url = something(data[I].url);\n            } catch (E) {\n                handle_error(E);\n            }\n        }\n    }\n}\n```\n\nThe loop becomes a nightmare now, right? Let's use lodash to reduce indents in the loop:\n\n```javascript\n_(data).each(function(V) {\n    try {\n        V.title = something(V.title);\n    } catch (E) {\n        handle_error(E);\n    }\n    try {\n        V.desciption = something(V.description);\n    } catch (E) {\n        handle_error(E);\n    }\n    try {\n        V.url = something(V.url);\n    } catch (E) {\n        handle_error(E);\n    }\n});\n\n```\n\nBut, lodash still can not reduce the try/catch hell for you. Now, JsonPathProcessor help on this!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzordius%2Fjson-path-processor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzordius%2Fjson-path-processor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzordius%2Fjson-path-processor/lists"}