An open API service indexing awesome lists of open source software.

https://github.com/tsmx/json-traverse

Traverse and manipulate JSON objects.
https://github.com/tsmx/json-traverse

json traverse

Last synced: 12 months ago
JSON representation

Traverse and manipulate JSON objects.

Awesome Lists containing this project

README

          

# [**@tsmx/json-traverse**](https://github.com/tsmx/json-traverse)

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
![npm (scoped)](https://img.shields.io/npm/v/@tsmx/json-traverse)
![node-current (scoped)](https://img.shields.io/node/v/@tsmx/json-traverse)
[![Build Status](https://img.shields.io/github/actions/workflow/status/tsmx/json-traverse/git-build.yml?branch=master)](https://img.shields.io/github/actions/workflow/status/tsmx/json-traverse/git-build.yml?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/tsmx/json-traverse/badge.svg?branch=master)](https://coveralls.io/github/tsmx/json-traverse?branch=master)

> Traverse and manipulate JSON objects.

## Usage

### Basic usage

```js
const jt = require('@tsmx/json-traverse');

const callbacks = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
/* your logic here */
},
enterLevel: (level, path) => {
/* your logic here */
},
exitLevel: (level, path) => {
/* your logic here */
}
};

var obj = { /* your JSON object */ };

jt.traverse(obj, callbacks);
```

### Example 1: print out a simple object

```js
var simpleObj = {
MyValue: 'test',
OtherValue: 'zzz',
NumberValue: 311,
MyArray: [1, 2, 3, 50, 60, 70]
};

const callbacks = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
console.log(level + ' ' + (path.length > 0 ? (path.join('.') + '.') : '') + key + ' = ' + value);
}
};

const jt = require('@tsmx/json-traverse');

jt.traverse(simpleObj, callbacks);
// 0 MyValue = test
// 0 OtherValue = xxx
// 0 NumberValue = 311
// 0 MyArray._0 = 1
// 0 MyArray._1 = 2
// 0 MyArray._2 = 3
// 0 MyArray._3 = 50
// 0 MyArray._4 = 60
// 0 MyArray._5 = 70

// flat array-mode: flattenArray = true (arrays are treated as one value)
jt.traverse(simpleObj, callbacks, true);
// 0 MyValue = test
// 0 OtherValue = xxx
// 0 NumberValue = 311
// 0 MyArray = 1,2,3,50,60,70
```

### Example 2: change values of an object

```js
var simpleObj = {
MyValue: 'test',
OtherValue: 'zzz',
NumberValue: 311,
MyArray: [1, 2, 3, 50, 60, 70]
};

const callbacks = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
// change values of properties starting with 'My' and
// multiply all numeric array values greater then 50 by 100
if (key.startsWith('My')) {
cbSetValue('MyNew-' + value);
}
if (isArrayElement && parseInt(value) > 50) {
cbSetValue(100 * parseInt(value));
}
}
};

const jt = require('@tsmx/json-traverse');

jt.traverse(simpleObj, callbacks);

// {
// MyValue : "MyNew-test",
// OtherValue: "xxx",
// NumberValue: 311,
// MyArray: [ 1, 2, 3, 50, 6000, 7000 ]
// }
```

### Example 3: convert a more complex object to a collapsible HTML list

```js
var htmlObj = {
MyArray: [0, 0],
ArrayInArray: [0, 1, ['two', 'three', [4, 5, 6]]],
MyNumber: 123,
MyString: 'test',
Child: {
ChildVal: 1,
SubChild: {
SubChildVal: 777
},
ChildArray: [1, 2, 66, 9, 900]
},
TrailingValue: 'testtesttest'
}

const callbacksHtmlList = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
if (isObjectRoot) {
console.log((' ').repeat(level) + '

  • Key: ' + key + '
  • ')
    }
    else {
    console.log((' ').repeat(level) + '
  • Key: ' + key + ', Value: ' + value + '
  • ')
    };
    },
    enterLevel: (level, path) => {
    if (level == 0) {
    console.log('
      ');
      }
      else {
      console.log((' ').repeat(level) + '
        ');
        };
        },
        exitLevel: (level, path) => { console.log((' ').repeat(level) + '
      '); }
      };

      const jt = require('@tsmx/json-traverse');

      jt.traverse(htmlObj, callbacksHtmlList, true);

      //


        //
      • Key: MyArray, Value: 0,0

      • //
      • Key: ArrayInArray, Value: 0,1,two,three,4,5,6

      • //
      • Key: MyNumber, Value: 123

      • //
      • Key: MyString, Value: test

      • //
      • Key: Child

      • //

          //
        • Key: ChildVal, Value: 1

        • //
        • Key: SubChild

        • //

            //
          • Key: SubChildVal, Value: 777

          • //

          //
        • Key: ChildArray, Value: 1,2,66,9,900

        • //

        //
      • Key: TrailingValue, Value: testtesttest

      • //

      ```

      ## Key-features

      - Define your callbacks for the following events:
      - `processValue`: processing a traversed value
      - `enterLevel`: entering a new nesting level
      - `exitLevel`: leaving nesting level
      - For every inspected value you will get rich meta-data
      - key name
      - level of nesting
      - `isObjectRoot` flag to indicate if it's an object root (root of a nested object)
      - `isArrayElement` flag to indicate if it's an array item
      - full path to the key as an array of path elements
      - Provides `cbSetValue` function to change any value in-place (directly in the traversed object)
      - Supports deep inspection of
      - Subobjects
      - Arrays
      - Arrays-in-Arrays
      - Subobjects-in-Arrays
      - Optional array flattening (treat arrays as flat values)

      ## API

      ### traverse(obj, callbacks = null, flattenArray = false)

      Traverse the `obj` and apply the defined callbacks while traversing.

      #### obj

      Type: `Object`

      The object to be traversed.

      #### callbacks

      Type: `Object`
      Default: `null`

      An Object containing the callback functions that should be applied while traversing `obj`. Every callback is optional. The expected form is:

      ```js
      callbacks = {
      processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
      /* your logic here */
      },
      enterLevel: (level, path) => {
      /* your logic here */
      },
      exitLevel: (level, path) => {
      /* your logic here */
      }
      };
      ```

      ##### processValue(key, value, level, path, isObjectRoot, isArrayElement, cbSetValue)

      Defined callback function that is executed on each value when traversing the object. Receives the following input parameters:

      ###### key

      Type: `String`

      The key of the current value that is processed. If an array is deep-inspected the key for each processed item is `_ + Index` (`_0`, `_1`, `_2`,...).

      ###### value

      Type: `String`

      The actual value for `key`.

      ###### level

      Type: `Number`

      The nesting level. `0` indicates the first level.

      ###### path

      Type: `Array`

      An array containing all keys that where passed to reach the current key/value pair. Example:

      ```js
      {
      child: {
      subchild: {
      myvalue: 123;
      }
      }
      }
      ```

      When processing the value `123` with key `myvalue`, path would be `['child', 'subchild' ]`.

      For deep-inspected arrays the path would contain the name of the array itself whereas the key would be the index of the processed value. Example:

      ```js
      {
      child: {
      subchild: {
      myvalues: [1, 2, 3]
      }
      }
      }
      ```

      When processing the array the keys would be `_0`, `_1` and `_2` and the path would always be `['child', 'subchild', 'myvalues']`.

      ###### isObjectRoot

      Type: `Boolean`

      `true` if the currently processed key is the root of another sub-object. In our example:

      ```js
      {
      child: {
      subchild: {
      myvalue: 123;
      }
      }
      }
      ```

      `isObjectRoot` would be `true` for the keys `child` and `subchild`.

      ###### isArrayElement

      Type: `Boolean`

      `true` if the currently processed key is an item of an array.

      ###### cbSetValue(newValue)

      Type: `Function`

      Callback function receiving the `newValue` that should replace the currently traversed `value`.

      **Note:** Setting a new value directly changes the traversed object! So if you need the original later on be sure to create a copy of the object first.

      ##### enterLevel(level, path)

      Defined callback function that is executed on entering a new nesting level when traversing the object. Receives the following input parameters:

      ###### level

      Type: `Number`

      0-based index of the nesting level that is entered.

      ###### path

      Type: `Array`

      An array containing all keys that where passed to reach the current level that is entered.

      ##### exitLevel(level, path)

      Defined callback function that is executed on leaving a nesting level when traversing the object. Receives the following input parameters:

      ###### level

      Type: `Number`

      0-based index of the nesting level that is exited.

      ###### path

      Type: `Array`

      An array containing all keys that where passed to reach the current level that is exited.

      #### flattenArray

      Type: `Boolean`
      Default: `false`

      If set to `true` arrays will not be iterated but treated as one single value. The default is `false`, where arrays are iterated and each entry is processed separately including deep-inspection, e.g. if the entry is an object or another array.