- Notifications
You must be signed in to change notification settings - Fork19
robtweed/qewd-transform-json
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Rob Tweedrtweed@mgateway.com
24 May 2023, MGateway Ltdhttps://www.mgateway.com
Twitter: @rtweed
Google Group for discussions, support, advice etc:http://groups.google.co.uk/group/enterprise-web-developer-community
Special thanks to the Ripple Foundationhttp://rippleosi.org forsupport and funding of this project.
npm install qewd-transform-json
qewd-transform-json is a simple, yet powerful way of transforming JSON from one format to another.
The use case for which it's designed is where you're doing repetitive processing that involvesinstances of a particular JSON document format being converted into some other JSON format.
qewd-transform-json takes an instance of an input JavaScript object, and transforms it to a new outputJavaScript object, using rules defined in a template object.
For example, the input object might look like this:
var inputObj = { foo: { bar1: 'hello', bar2: 'world' } };
The important feature of the template object is that it defines the structure of the new output object,as well as defining the value of each of its leaf nodes in terms of the input JSON document'sproperty paths.
Each element within the input object that is to be used as the value for an output object element isspecified within the template as a quoted string, within which the value is inside double curly braces.For example:
var templateObj = { a: '{{foo.bar1}}', b: { c: '{{foo.bar2}}', d: 'literal text', e: 'hello {{foo.bar2}} again' } };
Note thed property in the template above is defined as literal text without any curly braces,so the literal text value will be used in the output object as a fixed value.
Note also thee property in the template, showing how an input path reference can beembedded inside other literal text.
The module'stransform() function is then used to create the output object, eg
var transform = require('qewd-transform-json').transform; var newObj = transform(templateObj, inputObj);
The output would be:
{ "a": "hello", "b": { "c": "world", "d": "literal text", "e": "hello world again" } }
You can also specify that the output object is to contain an array which is mapped from somearray within the input object. For example, suppose the input object is:
var inputObj = { foo: { bar1: 'hello', bar2: 'world' }, arr: [ { name: 'Rob', city: 'London' }, { name: 'Chris', city: 'Oxford' }, ] };
We could map the names into an array within the output object by defining an array mapping rule in thetemplate. For example, see thepeople property in the template object below:
var templateObj = { a: '{{foo.bar1}}', b: { c: '{{foo.bar2}}' }, people: [ '{{arr}}', { firstName: '{{name}}' } ] };
people is defined as an array, containing two elements:
the first element defines the array property to use within the input object. In our case we want to useinput.arr, so we just specify {{arr}}.
the second element, if present, specifies the template object to create as each element of the outputarray.
Note that the input object properties you specify in the mappings are relative to the inputobject's parent arraythat you specified in the first element above. So, in the example above, they are relative to theinput object's{{arr}} array.Hence, for the output object'sfirstName property, you merely specify{{name}}, which tellsthe transformer to use thename property from each array element within the input object's *{{arr}} array.The template array object can be assimple or as complex as you like, and can define lower-level arrays and/or objects if required.
if the second element isn't defined, the array specified in the first element is copieddirectly into the output property.
The output object created from the example above would now look like this:
{ "a": "hello", "b": { "c": "world" }, "people": [ { "firstName": "Rob" }, { "firstName": "Chris" } ] }
Here's a more complex example:
// input object: var inputObj = { foo: { bar1: 'hello', bar2: 'world' }, level2: { arr: [ { name: 'Rob', address: { city: 'London' }, hobbies: ['cycling', 'hifi'] }, { name: 'Chris', address: { city: 'Oxford' }, hobbies: ['hill walking'] }, ] } }; // template object: var templateObj = { a: '{{foo.bar1}}', b: { c: '{{foo.bar2}}' }, people: [ '{{level2.arr}}', { firstName: '{{name}}', city: '{{address.city}}', likes: [ '{{hobbies}}' ] } ] };
The output object created from this transformation would be:
{ "a": "hello", "b": { "c": "world" }, "people": [ { "firstName": "Rob", "city": "London", "likes": [ "cycling", "hifi" ] }, { "firstName": "Chris", "city": "Oxford", "likes": [ "hill walking" ] } ] }
Often you'll want to be able to perform more complex transformations.
The transform module contains three pre-defined functions that you may find useful:
either(path, defaultValue) If the path doesn't exist or contains an empty string value in theinput object, then the literal string defined as the default value is used instead
getDate(path) If path is not defined (ie getDate() ), then the current date/time is returned inJavaScript date string format.
getTime(path) Uses the value of the specified input object path as a date, and returns it in getTime()format.
You can also define your own functions, eg:
var myFn = function(input) { return 'xxxxxx ' + input + ' yyyyyyy '; };
Then use the following syntax in the template:
property: '=> myFn(foo.bar1)',
Note that the value must be quoted, to ensure that it'sa valid object-literal property value, despite its special syntax. Spaces in the value will be ignored.
This tells the transformer to apply your myFn() function to the foo.bar1 property from the input object.
Finally, if you've defined your own custom function, you add a third argument to the transform() function,through which you pass your custom function, eg:
var newObj = transform(templateObj, inputObj, {myFn});
You may pass as many custom functions as you wish via this third argument.
Of course, this third argument isn't needed if you want to use any of the built-in functions.
So, for example:
var myFn = function(input) { return 'xxxxxx ' + input + ' yyyyyyy'; }; var inputObj = { foo: { bar1: 'hello', bar2: 'world', date: '2017-04-04' }, arr: [ { city: 'London' }, { name: 'Chris', city: 'Oxford' } ] }; var templateObj = { a: '{{foo.bar1}}', b: { c: '{{foo.bar2}}', d: 'literal text', e: '=> myFn(foo.bar2)', f: '=> either(foo.bar3, "foobar3!")', now: '=> getDate()', time: '=> getTime(foo.date)' }, people: [ '{{arr}}', { firstName: '=> either(name, "Rob")' } ] }; var newObj = transform(templateObj, inputObj, {myFn});
will create the following output object:
{ "a": "hello", "b": { "c": "world", "d": "literal text", "e": "xxxxxx world yyyyyyy", "f": "foobar3!", "now": "2017-04-04T17:14:20.266Z", "time": 1491264000000 }, "people": [ { "firstName": "Rob" }, { "firstName": "Chris" } ] }
You can even define functions that use more than one input argument, eg:
var myFn = function(input, input2) { return 'xxxxxx ' + input + ' yyyyyyy ' + input2 + ' zzzzz'; }; var templateObj = { a: '{{foo.bar1}}', b: { c: '{{foo.bar2}}', d: 'literal text', e: '=> myFn(foo.bar2, foo.bar1)' }, people: [ '{{arr}}', { firstName: '{{name}}' } ] };
This would produce the following output object:
{ "a": "hello", "b": { "c": "world", "d": "literal text", "e": "xxxxxx world yyyyyyy hello zzzzz" }, "people": [ { "firstName": "Rob" }, { "firstName": "Chris" } ] }
Copyright (c) 2023 MGateway Ltd,
Redhill, Surrey UK.
All rights reserved.
https://www.mgateway.com
Email:rtweed@mgateway.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions and
limitations under the License.