JBJ : transform Json By Json

A new way to transform JSON object with a JSON stylesheet. It's like XSL/XML but only with JSON.

Contributors

Installation

With npm do:

$ npm install jbj

Tests

Use mocha to run the tests.

$ npm install
$ npm test

Documentation

API

render(stylesheet : Object, input : Mixed, callback : Function) : None

Render input with stylesheet.

	var JBJ = require('jbj'),
	JBJ.render({ "truncate" : 3 }, "1234", function(err, out) {
			console.log(out);
	});

	// Output : 123

renderSync(stylesheet : Object, input : Mixed) : Object

Render input with stylesheet.

	var JBJ = require('jbj'),
	out = JBJ.renderSync({ "truncate" : 3 }, "1234");

	console.log(out);

	// Output : 123

register(protocol : String, callback : Function) : None

Add a function to fetch data for a specific protocol

	JBJ.register('http:', function request(urlObj, callback) {
		var buf = ''
	      , req = require('http').get(urlObj, function(res) {
			if (res.statusCode !== 200) {
				return callback(new Error('HTTP Error ' + res.statusCode));
			}
			res.setEncoding('utf8');
			res.on('data', function (chunk) {
			  buf += chunk.toString();
			});
			res.on('error', callback);
			res.on('end', function() {
			  callback(null, buf);
			});
		});
		req.on('error', callback);
	});

Adding filters/actions

To add a filter simply add a method to the .filters object:

	jbj.filters.concatx = function(obj, args) {
		return String(obj) + String(args) + 'X;
	};

Source

Stylesheet can contain a reference to data source. Source can be a file or an URL. By default, only the file: protocol is supported. Add your own protocol with register

	var stylesheet_1 = {
      "$?" : "https://raw.githubusercontent.com/castorjs/node-jbj/master/package.json",
      "$name" : {
        "upcase": true
      },
      "$main": {
        "upcase": true
      }
    };
	var stylesheet_2 = {
      "$name" : {
        "$?" : "file://" + path.resolve(__dirname, '../dataset/1.json'),
        "parseJSON" : true,
        "path": "name"
      },
      "$main": {
        "$?" : "file://" + path.resolve(__dirname, '../dataset/1.json'),
        "parseJSON" : true,
        "path": "main",
      }
    };

Variables

Variable can be set using $ plus a dot notation path.

	var stylesheet = {
		"$x" : {
			"get": "a.b.c",
		},
		"$y.y1.y2" : {
			"get": "a.d"
		}
	}

Actions

set: value

Set value and ignore input

	var stylesheet1 = {
		"set": "value"
	};
	var stylesheet2 = {
		"set": ["value", "value", "value"]
	};
	var stylesheet3 = {
		"set": {
			"a": 1,
			"b": 2
		}
	};

get: path | [path,path, ...]

aliases : find , path

Get value in input with some paths (with dot notation style)

	var stylesheet1 = {
		"set": {
			"a" : {
				"b" : {
					"c" : "Yo"
				}
			}
		},
		"get": "a.b.c"
	};
	// output : Yo
	var stylesheet2 = {
		"set" : {
			"a" : {
				"b" : 1,
				"c" : 2,
				"d" : 3
			}
		},
		"get": ["a.b", "a.c", "a.d"]
	};
// output : [1, 2, 3]

default: value

Fix value if input is not set

	var stylesheet = {
		var stylesheet = {
			"default": "value"
		};
	};

debug: none

Print input with console.log

	var stylesheet = {
		"set": "value",
		"debug": true
	};
	// output: value

foreach: stylesheet

Apply stylesheet on all elements of input

	var stylesheet1 = {
		"set": ["value", "value", "value"]
		"foreach" : {
			"upcase" : true
		}
	};
	// output : ["VALUE", "VALUE", "VALUE"]
	var stylesheet2 = {
		"set": [
			{ "b" : "x" },
			{ "b" : "y" }
		],
		"foreach" : {
			"get": "b",
			"upcase" : true
		}
	};
	// output : ["X", "Y"]
	var stylesheet3 = {
		"set": [
			{ "b" : "x" },
			{ "b" : "y" }
		],
		"foreach" : {
			"$b" : {
				"get": "b",
				"upcase" : true
			}
		}
	};
	// output : [ { "b" : "X" }, { "b" : "Y" } ]

extend: object

aliases : extendWith

Extend input with another object

	var stylesheet = {
		"set": {
			"a" : 1
		},
		"extend" : {
			"b" : 2
		}
	};
	// output : { a: 1, b: 2}

select: path | [path, path, ...]

Peck element(s) in input with "CSS selector"

	var stylesheet = {
		"set" : {
			"a" : {
				"b" : [
					{ "c" : "1" },
					{ "c" : "2" }
				]
			}
		},
		"select" : ".a > .b .#c"
	};
	// output : [1, 2]

for syntax see JSONSelect

mapping: object

Replace a value by the matching value in the object.

{
  "set": "one",
  "mapping": {
    "one": 1
  }
}
// output: 1
{
  "set": "FR",
  "mapping": {
    "US": "United States of America",
    "FR": "France"
  }
}
// output: "France"

Can also replace the values of an array with the matching values in the object.

{
  "set": [1, 2],
  "mapping": ["a","b","c"]
}
// output: ["b","c"]
{
  "set": ["a", "b"],
  "mapping": {
    "a": "Aha!",
    "b": "Baby"
  }
}
// output: ["Aha!","Baby"]

mappingVar: ["input","table"]

alias: combine

Replace the content of the input variable according to the content of the table variable.

var input = {
  "arg": { "a": "Aha!", "b": "Baby"},
  "input": "a"
};
var stylesheet = {
  "mappingVar": ["input", "arg"]
};
var output = JBJ.renderSync(stylesheet, input);
// output "Aha!";

array2object: [key, value]

Convert an array, which items have key and value properties, to an associative array (or object), which key properties are key values and values are value values.

Note: when the parameter is not a two items array, its default value is ["_id","value"].

Ex:

var stylesheet = {
  "set": [
    {
      "_id": "2007",
      "value": 538
    }, {
      "_id": "2008",
      "value": 577
    }, {
      "_id": "2009",
      "value": 611
  }],
  "array2object": true
};
// output = { "2007": 538, "2008": 577, "2009": 611 }

var stylesheet = {
  "set": [
    {
      "key": "2007",
      "val": 538
    }, {
      "key": "2008",
      "val": 577
    }, {
      "key": "2009",
      "val": 611
  }],
  "array2object": ["key","val"]
};
// output = { "2007": 538, "2008": 577, "2009": 611 }

zip: ["array1","array2"]

Join two arrays (which elements have an _id and a value keys).

var stylesheet = {
  "set": {
    "array1": [{"_id": "1", "value": 1},  {"_id": "2", "value": 2}],
    "array2": [{"_id": "1", "value": 10}, {"_id": "2", "value": 20}]
  },
  "zip": [ "array1", "array2" ]
};
var output = JBJ.renderSync(stylesheet);
// output: [ { _id: '1', array1: 1, array2: 10 },
//           { _id: '2', array1: 2, array2: 20 } ]

cast: (number|string|boolean) | [(string|date), pattern]

Convert input to specific type

	var stylesheet1 = {
		"set" : "1"
		"cast": "number"
	};
	// output : 1
	var stylesheet2 = {
		"set" : 1
		"cast": "string"
	};
	// output: "1"

for syntax see transtype

mask: pattern

Selecting specific parts of input, hiding the rest, return object

	var stylesheet = {
		"set" : {
			"a" : 1,
			"b" : 2,
			"c" : 3
		},
		"mask": "a,c"
	};
	// output : { a: 1, c: 3}

for syntax see json-mask

csv: separator

Pack input to CSV, return string

	var stylesheet = {
		"set" : ["x","y","z"],
		"csv" : ","
	};
	// output : "x,y,z"\r\n

parseCSV: separator

aliases : fromCSV, uncsv

Parse input as CSV string, return array

	var stylesheet = {
		"set" : "x,y,z",
		"parseCSV": ",",
	};
	// output : ["x","y","z"]

json: none

alias : toJSON

Pack input to JSON, return string

	var stylesheet = {
		"set" : ["x","y","z"],
		"json": true
	};
	// output : "[\"x\",\"y\",\"z\"]"

parseJSON:

aliases : fromJSON, unjson

Parse input as JSON string, return object

	var stylesheet = {
		"set" : "[\"x\",\"y\",\"z\"]",
		"parseJSON": true
	};
	// output : ["x","y","z"]

xml: options

Pack input to XML, return string

options are detailed in the xml-mapping documentation

	var stylesheet = {
		"set": {
			"root" : {
				"item" : [
					{ "index" : "1", "$t" : "A"},
					{ "index" : "2", "$t" : "B"},
					{ "index" : "3", "$t" : "C"}
				]
			}
		},
		"xml" : {
			"indent": false
		}
	};
	// output : <root><item index="1">A</item><item index="2">B</item><item index="3">C</item></root>

parseXML: options

aliases : fromXML, unxml

Parse input as XML string, return object

options are detailed in the xml-mapping documentation

	var stylesheet = {
		"set": "<root><item xml:id=\"1\">A</item><item xml:id=\"2\">B</item><item xml:id=\"3\">C</item></root>",
		"parseXML" : {
			"specialChar": "#",
			"longTag" : true
		}
	};
	// output : { root : { item : [ { xml#id: 1, #text: A }, { xml#id: 2, #text: B }, { xml#id: 3, #text: C } ] } }

coalesce: none

Get the first non-undefined value

	var stylesheet = {
		"set" : [null, undefined, null, "a", "b"],
		"coalesce": true
	};
	// output : "a"

required: none

If input is not set, return Error

trim: none

Trim input, return string

	var stylesheet = {
		"set" : "    xxx    ",
		"trim: true
	};
	// output : "xxx"

template: mustacheTemplate | [mustacheTemplate, mustacheTemplate, ...]

Build a string with mustache template and input

	var stylesheet = {
		"set" : {
			"a" : {
				"b" : "hello"
			},
			"c" : "world"
		},
		"template": "I say {{a.b}} to the {{c}}"
	};
	// output : I say hello to the world

compute: expression

Compute an expression with all variables of the input. Note : this variable contains input

	var stylesheet = {
		"set" : {
			"a" : 20,
			"b" : 3,
			"c" : 5,
			"d" : 8
		},
		"$x" : {
			"compute#1": "a / b",
			"compute#2": "round(this)",
			"cast": "number"
		},
		"$y" : {
			"path": "b",
			"cast": "number"
		},
		"$z" : {
			"compute": "x + y",
		}
	};
	// output : 10

assert: expression

If expression is true, then statements will be continued, otherwise it is stopped and it returns null Note : this variable contains input

	var stylesheet1 = {
		"set" : {
			"a" : 1
		},
		"$val#1" : {
			"assert": "a == 1",
			"set" : "if val"
		}
	};
	// output : "if val"
	var stylesheet2 = {
		"set" : {
			"a" : 0
		},
		"$val#1" : {
			"assert": "a == 1",
			"set" : "if val"
		},
	    "$val#2" : {
			"get" : "val",
	        "default": "else val",
		  }
	};
	// output : "else val"

capitalize:

Capitalize the first letter of input

	var stylesheet = {
		"set" : "xyz",
		"capitalize": true
	};
	// output : "Xyz"

downcase:

Downcase input

	var stylesheet = {
		"set" : "XYZ",
		"downcase": true
	};
	// output : "xyz"

upcase:

Uppercase input

	var stylesheet = {
		"set" : "xyz",
		"upcase": true
	};
	// output : "XYZ"

substring: [offset]|[offset, length]

aliases : substr

    var stylesheet = {
      "set"       : "20150310",
      "substring" : [4,2]
    };
    // output : "03"

first:

Get the first element of input

	var stylesheet = {
		"set" : ["a", "b", "c"],
		"first": true
	};
	// output : "a"

last:

Get the last element of input

	var stylesheet = {
		"set" : ["a", "b", "c"],
		"last": true
	};
	// output : "c"

sort:

Sort input object or array.

	var stylesheet = {
		"set": ["b", "c", "a"],
		"sort": true
	};
	// output : ["a", "b", "c"]

sortBy: prop | [prop, prop, ...]

aliases : sort_by

Sort input object the given prop ascending.

size:

aliases : length

Get the size or the length of input

	var stylesheet1 = {
		"set" : "12345",
		"size": true
	};
	var stylesheet2 = {
		"set" : [1,2,3,4,5],
		"size": true
	};
	// output : 5

max:

Add input and value

	var stylesheet1 = {
		"set" : [2, 4, 1, 7, 9, 3],
		"max" : true
	};
	// output : 9
	var stylesheet2 = {
		"set" : {a: 9, b: 4, c: 3, d: 5},
		"max" : true
	};
	// output : 9

min:

Subtract value from input

	var stylesheet1 = {
		"set" : [2, 4, 1, 7, 9, 3],
		"min" : true
	};
	// output : 1
	var stylesheet2 = {
		"set" : {a: 9, b: 4, c: 3, d: 5},
		"min" : true
	};
	// output : 3

plus: value | [value, value, ...]

Add input and value

	var stylesheet = {
		"set" : 4,
		"plus": 3
	};
	// output : 7
	var stylesheet = {
		"set" : 4,
		"plus": [1,2,3]
	};
	// output : [5,6,7]

minus: value | [value, value, ...]

Subtract value from input

	var stylesheet = {
		"set" : 4,
		"minus": 3
	};
	// output : 1
	var stylesheet = {
		"set" : 4,
		"minus": [1,2,3]
	};
	// output : [3,2,1]

times: value | [value, value, ...]

Multiply input by value"

	var stylesheet = {
		"set" : 5,
		"times": 5
	};
	// output : 25
	var stylesheet = {
		"set" : 4,
		"times": [1,2,3]
	};
	// output : [4,8,12]

dividedBy: value | [value, value, ...]

aliases : divided_by

Divide input by value"

	var stylesheet = {
		"set" : 10,
		"dividedBy": 2
	};
	// output : 5
	var stylesheet = {
		"set" : 4,
		"times": [1,2]
	};
	// output : [4,2]

join: string = ', '

aliases : glue

Join input with the given string.

	var stylesheet = {
		"set" : ["a","b","c"],
		"join": " | "
	};
	// output : "a | b | c"

shift: n | [n, n, ...]

Shift input to the left by n

	var stylesheet = {
		"set" : "The world",
		"shift": 4
	};
	// output : "world"
	var stylesheet = {
		"set" : [1,2,3,4,5],
		"shift": 2
	};
	// output : [3,4,5]
	var stylesheet = {
		"set" : [1,2,3,4,5],
		"shift": [2,3]
	};
	// output : [[3,4,5],[4,5]]

truncate: length | [length, length, ...]

Truncate input to length.

	var stylesheet = {
		"set" : "hello world",
		"truncate": 5
	};
	// output : "hello"

truncateWords: n | [n, n, ...]

aliases : truncate_words

Truncate input to n words (separator: space).

	var stylesheet = {
		"set" : "This is JBJ!",
		"truncateWords": 2
	}
	// output "This is"
	var stylesheet = {
		"set" : "This is JBJ!",
		"truncateWords": [1,2]
	}
	// output ["This","This is"]

replace: [pattern, substitution] | pattern

Replace pattern with substitution in input.

	var stylesheet = {
		"set" : "XoXoXoX",
		"replace": ["o", "."]
	};
	// output :  X.X.X.X
	var stylesheet = {
		"set" : "XoXoXoX",
		"replace": "o"
	};
	// output :  XXXX

prepend: something | [something, something, ...]

Prepend something to input

	var stylesheet = {
		"set" : "world"
		"prepend": "hello"
	};
	// output : "hello world"
	var stylesheet = {
		"set" : "h"
		"prepend": ["a","e","i","o","u"]
	};
	// output : ["ah","eh","ih","oh","uh"]

append: something | [something, something, ...]

Append something to input

	var stylesheet = {
		"set" : "cool",
		"append": "!"
	};
	// output : "cool!"
	var stylesheet = {
		"set" : "cool",
		"append": ["!","?","."]
	};
	// output : ["cool!","cool?","cool."]

reverse:

Reverse items order of input

	var stylesheet = {
		"set" : [1,2,3]
	};
	// output : [3,2,1]

flatten:

Flatten an array.

    var stylesheet = {
      "set"     : [ ['a', 'b'], ['c', 'd'], 'e'],
      "flatten" : true
    };
	// output : ["a","b","c","d","e"]

deduplicate:

aliases : dedupe , unique

Deduplicate values in an array.

    var stylesheet = {
      "set"         : [ 1, 2, 3, 1, 2],
      "deduplicate" : true
    };
	// output : [1,2,3]

remove:

alias : del

Remove one value in an array.

    var stylesheet = {
      "set"    : [ 1, 2, 3],
      "remove" : 2
    };
	// output : [1,3]
    var stylesheet = {
      "set"    : [ "a", "", "b"],
      "remove" : ""
    };
    // output : ["a","b"]
    var stylesheet = {
      "set"    : [ "a", "b", "c"],
      "remove" : "b"
    };
    // output : ["a","c"]

getindex: property | index

aliases : getProperty, getproperty, getIndex

Get a property of an object, or an item of an array.

var stylesheet = {
  "set"        : [ "a", "b", "c" ],
  "getindex": "2"
};
// output : "c"
var stylesheet = {
  "set"        : { "a": 0, "b": 1, "c":2 },
  "getproperty": "b"
};
// output : 1

getindexvar: [ arrayName | objectName , propertyName | indexName ]

aliases : getPropertyVar, getpropertyvar, getIndexVar

Get a property of an object, or an item of an array, like getindex, but using variables.

var stylesheet = {
  "set": {
    "i": 1,
    "t": ["a","b","c"]
  },
  "getIndexVar": ["t", "i"]
};
// output : "b"
var stylesheet = {
  "set": {
    "i" : "b",
    "o" : { "a": 0, "b": 1, "c":2 },
  },
  "getPropertyVar": ["o", "i"]
};
// output : 1

sum:

alias : total

Return the sum of all the value of an array.

    var stylesheet = {
      "set"    : [ 1, 2, 3],
      "sum" : true
    };
	// output : 6

FAQ

How to chain the same action

just add #

	var stylesheet = {
		"default":  "123456789",
		"truncate#1": 8,
		"truncate#2": 4,
		"truncate#3": 2
	};

How to use input as variable in an expression

just use this

	var stylesheet = {
      "$e" : {
        "compute#1": "a / b",
        "compute#2": "round(this)",
        "cast": "number"
      }
    }

How to find more examples

see unit tests : https://github.com/castorjs/node-jbj/tree/master/test

Try it

http://castorjs.github.io/node-jbj/

Also

License

MIT