Is there a way to utilize JSON parse for converting deeply nested keys from underscore to camelCase?

A JSON string containing an object is on my mind:

const str = `[{"user_id":"561904e8-6e45-5012-a9d8-e2ff8761acf6","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="caa0a3a6a5bc8aacaba1afe4a9a5a7">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]}]`;

I am interested in parsing this string using JSON.parse, while simultaneously converting every underscore key to camelCase at all levels.

Can this be achieved with a single function that performs both tasks? Or do I need to handle them separately?

Answer №1

Since you inquired about using the reviver method in the comment, here is a solution that demonstrates its usage.

However, the effectiveness of this approach is debatable.

It relies on the strategy employed during the reviving process, as outlined in 25.5.1 JSON.parse ( text [ , reviver ] ) and 25.5.1.1 InternalizeJSONProperty ( holder, name, reviver ), indicating that it should function correctly.

Yet, caution is advised when relying on this method, as the primary intent of the reviver functionality may not align with this particular use case. It might be better to reimplement the traversal logic instead.

this within the reviver callback pertains to the container that encompasses both key and value.

const str = `[{"user_id":"561904e8-6e45-5012-a9d8-e2ff8761acf6","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="69030005061f290f08020c470a0604">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]},{"user_id":"5904003b-452b-535c-9615-94706bf6c66c","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="40332137350026212b256e232f2d">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]}]`

const snakeToCamel = str => str.replace(/([-_]\w)/g, g => g[1].toUpperCase());

var parsed = JSON.parse(str, function(key, value) {
  const camelCaseKey = snakeToCamel(key)
 
  if (this instanceof Array || camelCaseKey === key) {
    // if this is Array 
    // or key does not change after converted to camel case
    // then just return the value so that the default "reviving" is done
    return value
  } else {
    // if key changes assing value to camel case one and return nothing
    this[camelCaseKey] = value
  }
});

console.dir(parsed)

source of snakeToPascal

Answer №2

Check out this solution I came up with:

const str = `[{"user_id":"561904e8-6e45-5012-a9d8-e2ff8761acf6","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ec868580839aac8a8d8789c28f8381">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]},{"user_id":"5904003b-452b-535c-9615-94706bf6c66c","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2e5d4f595b6e484f454b004d4143">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]}]`;
let obj = JSON.parse(str);


function snakeToCamel(str) {
    const splitString = str.split('_');
    let result = "";
    splitString.forEach((sstr, iter) => {
        if (iter !== 0) {
            result += sstr.charAt(0).toUpperCase() + sstr.slice(1);
        } else
            result += sstr;

    })
    return result;
}

function convertToCamelCase(target) {
    const keys = Object.keys(target);
    keys.forEach(key => {
        if (typeof target[key] === 'object')
            convertToCamelCase(target[key]);

        const converted = snakeToCamel(key);
        if (key !== converted) {
            target[converted] = target[key];
            delete target[key];
        }
    });
}

convertToCamelCase(obj)
console.log(obj);

Answer №3

I have just created a solution for that issue in the form of a playground. Feel free to explore it here, and I must say, it was quite an enjoyable problem.

const str = `[{"user_id":"561904e8-6e45-5012-a9d8-e2ff8761acf6","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="711b181d1e073117101a145f121e1c">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]},{"user_id":"5904003b-452b-535c-9615-94706bf6c66c","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7c0f1d0b093c1a1d1719521f1311">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]}]`;
const obj = JSON.parse(str);

function toCamelCase(snake_case) {
  return snake_case.replace(/([-_][a-z])/ig, ($1) => {
    return $1.toUpperCase()
      .replace('-', '')
      .replace('_', '');
  });
}

function transformObject(obj) {
  if (obj && Array.isArray(obj)) {
    return obj.map(e => transformObject(e));
  }
  if (obj && typeof obj === "object") {
    const final = {};
    for (const [key, val] of Object.entries(obj)) {
      final[toCamelCase(key)] = transformObject(val);
    }
    return final;
  }
  return obj;
}
const transformed = transformObject(obj);
console.log(transformed);

Answer №4

A straightforward approach is to use the Array.reduce() method along with a recursive function for camelCase modification. This solution is adaptable and can handle deeply nested data structures effectively.

const jsonData = `[{"user_id":"561904e8-6e45-5012-a9d8-e2ff8761acf6","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="543e3d383b221432353f317a373b">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]},{"user_id":"5904003b-452b-535c-9615-94706bf6c66c","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3a495b4d4f7a5c5b515f14595557">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]}]`;

const mapToCamelCase = (data) => {
  return Object.fromEntries(Object.entries(data).map(item => {
    if (Array.isArray(item[1])) item[1] = item[1].map(element => mapToCamelCase(element));
    item[0] = item[0].split('_').map((word, index) => index === 0 ? word : word.slice(0, 1).toUpperCase() + word.slice(1)).join('');
    return item;
  }))
}
let modifiedData = JSON.parse(jsonData).reduce((acc, current) => ([...acc, mapToCamelCase(current)]), [])

console.log(modifiedData)

Answer №5

By applying a simple reduction technique without using regex, you can achieve the following:

function convertSnakeCaseToCamelCase(str){
  var flag = false;
  return Array.prototype.reduce.call( str
                                    , (result,char) => char === "_" ? ( flag = true
                                                           , result
                                                           )
                                                         : result += (flag ? ( flag = false
                                                                     , char.toUpperCase()
                                                                     )
                                                                   : char)
                                    , ""
                                    );
}
var inputData = `[{"user_id":"561904e8-6e45-5012-a9d8-e2ff8761acf6","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bad0d3d6d5ccfadcdbd1df94d9d5d7">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]},{"user_id":"5904003b-452b-535c-9615-94706bf6c66c","email_addr":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d2a1b3a5a792b4b3b9b7fcb1bdbf">[email protected]</a>","details":[{"city_name":"fake city","country_name":"fake country"}]}]`;

console.log(JSON.parse(convertSnakeCaseToCamelCase(inputData)));
.as-console-wrapper {
  max-height: 100% !important;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to redirect the user directly to the upload page without displaying the response?

Recently, I came across this code snippet that adds a progress bar to an upload form. Currently, the code displays the response from the upload page below the form. However, my goal is to redirect the user to the upload page so they can view the response t ...

Tips for handling promise coverage within functions during unit testing with Jest

How can I ensure coverage for the resolve and reject functions of a promise within a function while conducting unit tests using Jest? You can refer to the code snippet below. Service.js export const userLogin = data => { return AjaxService.post( ...

`Developing reusable TypeScript code for both Node.js and Vue.js`

I'm struggling to figure out the solution for my current setup. Here are the details: Node.js 16.1.x Vue.js 3.x TypeScript 4.2.4 This is how my directory structure looks: Root (Node.js server) shared MySharedFile.ts ui (Vue.js code) MySharedFi ...

Displaying an additional section using hover effects in Bootstrap

I recently utilized Bootstrap to create pricing tables which can be viewed here: http://www.bootply.com/VyHsJBDoNc Is there a way for me to implement hover functionality on a span element (+ More Information!) that will display additional information as s ...

Leveraging class names to dynamically apply CSS styles to components based on their props value

In the process of developing a collection of reusable components, I have utilized material-ui and styled them with CSS. One specific requirement is to dynamically set the width of a component through a prop passed into a custom button. My goal is to lever ...

Elegant Bootstrap 4 Carousel featuring a glimpse of the upcoming slide alongside the primary carousel item

I am in search of a straightforward Bootstrap 4 carousel that showcases a glimpse of the next slide on the right. Despite exploring similar questions, I have not found a suitable solution. The links to those questions are: 1)Bootstrap carousel reveal part ...

Properly maintaining child processes created with child_process.spawn() in node.js

Check out this example code: #!/usr/bin/env node "use strict"; var child_process = require('child_process'); var x = child_process.spawn('sleep', [100],); throw new Error("failure"); This code spawns a child process and immediately ...

What is the process for configuring simultaneous services on CircleCI for testing purposes?

My current project involves running tests with Jasmine and WebdriverIO, which I want to automate using CircleCI. As someone new to testing, I'm a bit unsure of the process. Here's what I've gathered so far: To run the tests, I use npm tes ...

Combining two asynchronous requests in AJAX

In the process of customizing the form-edit-account.php template, I have added ajax requests to enhance the functionality of the account settings form. The form allows users to modify their name, surname, age, and other details. While the ajax implementati ...

Issue found in React Js test - TypeError: source.on does not exist as a function

I'm encountering an issue with my post request using multipart/form-data. Everything runs smoothly, except for the tests which are failing. When running the tests, I encounter an error message: TypeError: source.on is not a function. This is the code ...

The search for 'partition' in 'rxjs' did not yield any results

Recently, I attempted to incorporate ng-http-loader into my Angular project. After successfully installing the ng-http-loader package, I encountered an error during compilation. The specific error message displayed was: export 'partition' was ...

After the table finishes loading, my goal is to display an export to Excel button

I am currently working on generating an HTML table using JSON data received from the backend Java application. My objective is to display an "Export to Excel" button after populating the table. The process involves users entering dates and selecting option ...

Vue JSON Response Guide

Inquiry from a beginner. My goal is to display the name of a city using props. When I use {{ props.feed.location }} to fetch: { "latitude": 50.85, "longitude": 4.35, "name": "Brussels, Belgium", "id": 213633143 } However, when I attempt {{ props.feed.l ...

Does an href and click events both happen simultaneously?

JavaScript Purpose: Implement a series of loops and create anchor links with the 'href' attribute <a class="mui-control-item" v-for="(item, index) in dai" v-on:click ="abc(item)" :href="'#item'+(index+1)+ 'mobile'" ...

Leveraging the Power of CSS in Your Express Applications

Struggling to make my CSS links functional while working on localhost. Currently, when I view Index.html on my server, it displays as plain text without any styling. Even after trying the express middleware, the CSS files are still not being served, result ...

Submitting an image blob to a database using the FormBuilder

I'm facing an issue with uploading a file blob into the same DB as my form. Here is my form: this.accForm = this.formBuilder.group({ team_leader: ['', Validators.required], hotel_name: ['', Validators.required], address: [&a ...

Performing mathematical operations in JavaScript, rounding to the nearest .05 increment with precision up to two

Apologies in advance. After reviewing multiple posts, it seems like the solution involves using the toFixed() method, but I'm struggling to implement it. $('.addsurcharge').click(function() { $('span.depositamount&ap ...

Encountering the error "undefined object" while using the yield keyword in JavaScript

var pi = document.getElementById("pi"); function * calculatePi(){ let q = 1; let r = 0; let t = 1; let k = 1; let n = 3; let l = 3; while (true){ if (4*q+r-t < n*t){ alert(n); yield n; ...

A step-by-step guide on incorporating universal CSRF tokens using JQuery AJAX

As part of my development work, I am in the process of creating jquery code that communicates with the server through ajax to input data into a database based on specific request parameters. My main concern at this point is the vulnerability to CSRF attac ...

Looking for suggestions on AngularJS and Rails integration!

I'm currently in the process of creating a website using rails, but I want to integrate AngularJS for several reasons: Efficient sorting between 2 different types of data (such as selecting various restaurants from a list and then different food cate ...