Coder Social home page Coder Social logo

qewd-transform-json's Introduction

qewd-transform-JSON: Transform JSON using a template

Rob Tweed [email protected]
24 May 2023, MGateway Ltd https://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 Foundation http://rippleosi.org for support and funding of this project.

Installing

   npm install qewd-transform-json

Using qewd-transform-json

Simple Transformations

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 involves instances 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 output JavaScript 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's property paths.

Each element within the input object that is to be used as the value for an output object element is specified 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 the d 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 the e property in the template, showing how an input path reference can be embedded inside other literal text.

The module's transform() 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"
    }
  }

Substituting Arrays

You can also specify that the output object is to contain an array which is mapped from some array 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 the template. For example, see the people 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 use input.arr, so we just specify {{arr}}.

  • the second element, if present, specifies the template object to create as each element of the output array.
    Note that the input object properties you specify in the mappings are relative to the input object's parent array that you specified in the first element above. So, in the example above, they are relative to the input object's {{arr}} array. Hence, for the output object's firstName property, you merely specify {{name}}, which tells the transformer to use the name property from each array element within the input object's *{{arr}} array.

    The template array object can be as simple 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 copied directly 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"
        ]
      }
    ]
  }

Applying Your Own Custom Transformation Functions

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 the input 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 in JavaScript 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's a 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"
      }
    ]
  }

License

Copyright (c) 2023 MGateway Ltd,
Redhill, Surrey UK.
All rights reserved.

https://www.mgateway.com
Email: [email protected]

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.

qewd-transform-json's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

qewd-transform-json's Issues

Get parent DATA from array element

I cant get parent data from child array, for example

var templateObj = {
JobNumber: "{{job.number}}",
Periods: ['{{motor.vehicles}}', {
ExternalID: "{{ROOT_INPUT_OBJECT.number}}",

Cannot read property 'init' of undefined

When trying to transform any json i get the above mentioned error. I get the same error while running test.js. This is becasue the helpers in the transform function is undefined. Could you please resolve this or let me know if i am doing something wrong.

Issue parsing array with multiple values

var transform = require('qewd-transform-json').transform;  

var data = {
  "name": "Hello {{user.name}}",  
  "primary_task": "{{user.tasks[0].name}}",
  "secondary_tasks": ["X {{user.tasks[0].name}}", "Task 2"]
}

var metadata = {
  "user": {
    "name": "DJ",
    "tasks": [
    {
      "name": "Task 1"
    }
  ],
  },  
};

var newObj = transform(data, metadata);

Above code fails to transform values if an array has more than 1 element. Here is the output of the above transformation:

{"name":"Hello DJ","primary_task":"Task 1","secondary_tasks":[]}

Update documentation for String.format capabilities

The current syntax also supports String.format capabilities as it replaces the value found in the mustache variable.

So instead of using functions for string formats we could just use the format capabilities

name: "{{firstName}} {{lastName}}",
This would provide the value
name: "John Doe"
Without having a custom function

Change instruction on npmjs.com

Thanks for the great package.
The instructions at
https://www.npmjs.com/package/qewd-transform-json

npm install qewd-transform-JSON
needs to be changed to
npm install qewd-transform-json

As npm no longer supports capital case package names .

`npm ERR! code E404  
npm ERR! 404 Not Found - GET https://registry.npmjs.org/qewd-transform-JSON - Not found  
npm ERR! 404   
npm ERR! 404  'qewd-transform-JSON@latest' is not in the npm registry  
npm ERR! 404 Your package name is not valid, because  
npm ERR! 404  1. name can no longer contain capital letters`  

Object path issue in transform.js

I've used this for an AWS Lambda function and so had to choose node 6.1 in the config to support the Spread Operator used in tarnsform.js.

When I did this I noticed that the transform wasn't working.
I identified the problem as being in the getActualValue function, where there is a function fn to return the value of the given item in the data object.
However in node 6.1 I had to first convert the data object from a string using JSON.parse.
Once I had done this the fn worked as expected.

So the fix I believe is to just add a line above the fn so that we first convert data into a proper JSON object so that the function can then identify the path to the items in the JSON structure.

To be honest I haven't tried this new code outside of Lambda.

It did work unchanged in my local Ubuntu 16.04 install, but on Lambda didn't until I made the changes.
I will try to prove that the change I made also works in my non-Lambda environment too and post back.

Web version

Hello,
Do you have web version of traverse and qewd-transform-json files

Add a transform method for async

Since the string manipulation operations tends to be heavy as the object increases, can a async method be written too for those transforms that are heavy.

Ability to remove map fields which are empty

Have a flag on the transform to remove empty fields.

One could have a map with 2 fields
F1->Mapped to DataField DF1
F2->Mapped to Data Field DF2

If the data doesn't have DF2, there should be a provision on the transform to say remove this field
So the output when there is no DF2 field should only be F1->DF1 and the empty F2 which did not receive a value from DF2 should be removed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.