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

Utilizing Angular's DomSanitizer to safely bypass security scripts

Exploring the capabilities of Angular's bypassSecurityTrust* functions has been a recent focus of mine. My objective is to have a script tag successfully execute on the current page. However, I keep encountering issues where the content gets sanitized ...

Incorporating a personalized image to create custom icons on the Material UI bottom navigation bar

Is it possible to replace the default icon with a custom image in material ui's BottomNavigation component? I'm curious if Material UI supports this feature. If you'd like to take a closer look, here is the link to the codesandbox. ...

The rsuite table does not properly reflect changes in state data

This is the render method that I am working on render() { return ( <Contentbox> <ol> {this.state.data.map((obj) => ( <li key={obj._id}>{obj.name}</li> ) ...

"Combining Array Elements in jQuery: A Guide to Merging Two Array Objects

enter : var b= [{ "cat_id": "1", "cat_name": "teaching" }]; var a= [ { "username": "r", "password": "r" }]; I desire the following result: [{"username":"r","password":"r","cat_id":"1","cat_name":"teaching"}] ...

The querySelector function seems to be identifying the element with the ID "submit" and another input element of type "submit"

My code includes a function that toggles between two elements' style.display values, switching them from "none" to "block" and vice versa. However, I've encountered an unexpected issue where the behavior of the "send" button seems to be linked wi ...

The CSS property overflow:hidden or overflow:scroll is not functioning as expected when applied to a

On my practice website, I have set up a demonstration for showcasing text data. The issue arises when the user inserts an excessive amount of characters in the text box. To address this, I would like the text to be scrollable so that all content can be d ...

Tips for properly modifying an attribute within an array of objects in JavaScript using ReactJS

My array of objects looks like this: this.state = { itemSquare: [{ item: "bomb", status: false }, { item: "bomb", status: false }, { item: "bomb", status: false }, { item: "bomb", status: ...

Importing modules using relative paths results in failure due to module not being found, whereas employing absolute paths

I have been encountering this problem for a considerable amount of time and have made multiple attempts to resolve it. I am currently working on the development of my discord.js bot and recently switched from TS back to JS due to certain complications I fa ...

Is the JavaScript Array simply a figment of our imagination

This may appear to be a small and insignificant issue, but I am struggling to find a solution. Within this function, var q is set to an array of strings. When the function is called, alert(q) successfully displays the entire array. function initializeQui ...

Tips for utilizing the window object in Angular 7

To implement the scrollTo() function of the window object directly, we can use window.scrollTo(0,0). However, when researching how to do this in Angular, I found that many people create a provider as shown below: import {InjectionToken, FactoryProvider} f ...

An issue has arisen while trying to run NPM start on ReactJS

Having trouble starting npm (ReactJS) Whenever I try to run the terminal command npm start An error message is displayed: ERROR in multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server /index.js Module not found: Error: Can& ...

What is the best way to display an image in HTML?

I have successfully created an autocomplete search box that retrieves product names, but I am struggling to display the product photos. Here is the code snippet I am using: <asp:TextBox ID="txtContactsSearch" runat="server" Width="261"></asp:Text ...

The received reply does not align with the set parameter configuration:

Encountering an issue with Angular $resource: error description Error: error:badcfg Response does not match configured parameter: Error in resource configuration for action `array`. Expected response to contain an object but got an {2} Initialization of ...

Struggling to locate the index of the matching object within an array of objects?

There is a dataset available: var data = { "variants": [{ "quantity": "20", "varientId": 8, "currency": "YEN", "extraField": { "Size": "1 ...

How can I create a menu of buttons in Vue that open individual windows with unique URLs when clicked?

Javascript Code: function InitializeVue() { var vueOptions = { el: '#activeEvents', data: { activeEvents: [] } }; vueInstance = new Vue(vueOptions); } HTML Code: <table id="activeEvents"> ...

Creating a Dojo HTML template involves incorporating repetitive sections of HTML code within the template structure

I am working with a custom Dojo widget that is based on a template and has an HTML template stored in a separate .html file. Here is the Dojo Widget code snippet: define("dojow/SomeWidgetName",[ "dojo/_base/declare", "dijit/_WidgetBase", "dijit/_Templat ...

What sets apart jQuery.ajax's dataType="json" from using JSON.parse() for parsing JSON data?

What is the difference between using dataType='json' and parsing response with JSON.parse(response) in jQuery Ajax? $.ajax({ url: path, type: 'POST', dataType: 'json', data: { block ...

Sending various types of data to an MVC C# controller using AJAX

Currently, I am utilizing AJAX to retrieve information from a Razor View and forward it to the controller. Although everything is functioning as expected, I now face the challenge of passing an array along with a string as the data: // View - JavaScript v ...

Enhance your jQuery experience by customizing the .click function

When designing my website, I wanted it to be functional on both touch devices and desktops that do not have touch capabilities. To ensure a smooth user experience on touch devices, I implemented the tappy library to eliminate the 300ms delay on jQuery .cli ...

What can be done to resolve the issue of 'this.state.*.map' not being a function

I am encountering an issue while trying to export a single row from my component import React, {Component} from 'react'; class TableRow extends Component { state = { row: [] }; componentWillMount() { this.setState({row: this.props.chil ...