Any ideas on how I can adjust this basic JSON to avoid triggering the "Circular structure to JSON" error?

Learning Journey

I am currently teaching myself JavaScript and exploring JSON along the way. My current project involves developing a JavaScript WebScraper where I plan to store my results in JSON format.

While I am aware of other methods like using databases, server-client interactions, etc., my primary focus at the moment is on understanding JSON - how to parse, create, and format it. This serves as a valuable learning opportunity for me.

Understanding Variables

The data stored in the aforementioned variables originates from an HTML file. To illustrate, here's an example of the content:

users[] -> "<a href=\"countries.php?id=1\">Egypt</a>"
GDP[] -> "<td> $2,971</td>"
Regions[] -> "<td> Egypt </td>"
Align[] -> "<td> Eastern Bloc </td>"

Creative Coding

let countries = [];
for(let i = 0; i < users.length; i++)
{
    countries.push( {
        'country' : [{
            'name' : users[i],
            'GDP' : GDP[i],
            'Region' : regions[i],
            'Align' : align[i]

    }]})
};



let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);

Decoding the Code

Prior to this code snippet, I had populated arrays (users, GDP, regions, align) with data extracted in string format from a website. The subsequent idea was to encapsulate this data into an object and utilize the stringify() function to convert it into JSON.

Upon testing this implementation without the loop (with static test data), it proved to be functional.

Error Investigation

let obj_data = JSON.stringify(countries, null, 2);
                        ^

TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Node'
    |     property 'children' -> object with constructor 'Array'
    |     index 0 -> object with constructor 'Node'
    --- property 'parent' closes the circle

Query Clarification

My goal with this question is to comprehend what causes this JSON format to become "Circular" and strategize solutions to make this code align with my objectives.

End Notes

  • I'm working within Node.js and Visual Studio Code environment

Additional Insights

Successfully Tested Code Snippet

let countries;
    console.log(users.length)
    for(let i = 0; i < users.length; i++)
    {
        countries = {
            
            country : [
                {
                    "name" : 'CountryTest'
                }
            ]
        } 
            
    };
     
    let obj_data = JSON.stringify(countries, null, 2);
    fs.writeFileSync('countryballs.json', obj_data);    
});

Comparing this revised code sample to the initial version, note that I manually input the country name here. This approach has proven to work flawlessly:

https://i.sstatic.net/xtVF2.jpg

By substituting 'CountryTest' with `users[i]` containing country names, the circular error emerges once more, prompting a partial solution by adding `+""`:

Enhanced Code Example:

 for(let i = 0; i < users.length; i++)
    {
        countries = {
            
            country : [
                {
                    "name" : users[i]+''
                }
            ]
        }   
    };

This adjustment leads to:

https://i.sstatic.net/ehIec.jpg

Unresolved Bug

Despite these modifications, only one country is displayed out of the 32 present in the `users[]` array. This discrepancy raises doubts regarding the provided solutions so far.

Preferred JSON Structure

{
  "countries": {
    "country": [
      {
        "name": "",
        "GDP" : "",
        "Region" : "",
        "Align" : ""
      },
      {
        "name": "",
        "GDP" : "",
        "Region" : "",
        "Align" : ""
      },
      {
        "name": "",
        "GDP" : "",
        "Region" : "",
        "Align" : ""
      }
      
    ]}
}

Answer №1

An issue known as circular structure error occurs when an object references itself either directly (a -> a) or indirectly (a -> b -> a).

To prevent this error, you can instruct JSON.stringify on how to handle circular references. For instance, if one person object points to another person object ("parent"), which in turn may point back to the original person, you can use the following approach:

JSON.stringify( that.person, function( key, value) {
  if( key == 'parent') { return value.id;}
  else {return value;}
})

The second argument passed to stringify is a filter function. In this case, it simply converts the referenced object to its ID. However, you have the flexibility to implement any logic to resolve the circular reference.

You can test the code snippet above with the following example:

function Person( params) {
  this.id = params['id'];
  this.name = params['name']; 
  this.father = null;
  this.fingers = [];
  // additional properties
}

var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him; 
JSON.stringify(me); // no issues so far

him.father = me; // assuming time travel :-)
JSON.stringify(me); // throws "TypeError: Converting circular structure to JSON"
// To resolve, you can use:
JSON.stringify(me, function( key, value) {
  if(key == 'father') { 
    return value.id;
  } else {
    return value;
  };
})

This solution was found on a StackOverflow thread titled,

Stringify (convert to JSON) a JavaScript object with circular reference

Answer №2

It appears that the variable users contains a list of DOM nodes in your output. To avoid potential cyclical structures, if you only need their text content, you can access it by extracting the text information like this:

country : [
    {
        "name" : users[i].textContent // maybe also followed by `.trim()
    }
]

Alternatively, you could extract all the text from the list upfront as follows:

const usersText = [...users].map(node => node.textContent)

Then, you can use the array usersText instead of directly using the users variable while constructing your object.

If variables like GDP, regions, and align are also pointing to HTML elements, you may need to follow a similar approach with them as well.

Answer №3

Breakthrough!

Contrary to what was previously suggested, the issue at hand is not one of circularity within the JSON design. Instead, it stems from errors in the data itself.

When I collected the data, it was in html format like <td>whatever</td>, which I overlooked initially assuming I could remove it later. My main focus was on ensuring well-formatted JSON and gaining knowledge.

Following insights from @VLAZ and @Scott Sauyezt, it seems that improperly formatted data may inadvertently refer to itself, prompting me to address this aspect.

Let's investigate this hypothesis further...

To extract the data, I utilized cheerio.js, a tool akin to jquery for parsing html.

In retrieving the country name, I used:

nullTest = ($('table').eq(2).find('tr').eq(i).find('td').find('a').last());
            //"Partial solution" for the OutOfIndex nulls
            if (nullTest != null)
            {
                users.push(nullTest);                
            }

(Utilizing nullTest helps avoid null values, with plans to refine the code using RegEx once everything functions smoothly)

This query would yield results such as:

<a href="source">whatEverIsInHereIfThereIsAny</a>

Alternatively,

To strip away the html tags, simply append .html() at the end of the jquery statement like so:

($('table').eq(2).find('tr').eq(i).find('td').find('a').last().html());

This approach converts the output into strings, effectively mitigating potential errors and resolving the underlying question.

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

Reset filter when the "All" option is chosen in Vue.js

There is an array of objects that looks like this: obj= [{name: 'joe', job: 'teacher', city: 'miami'}, {name: 'bill', job: 'police', city: 'yorkshire'}, {name: 'sarah', job: 'driver ...

parse a complex JSON object

Here is the JSON string that I am dealing with: { 'studentinfo': { 'name':'abc', 'age':41, 'gender':male, address: { 'street':'asd', 'city':'ipd', 'state' ...

Tips for Dynamically Binding Data in Angular ChartsWant to learn how to dynamically bind

I have integrated angular-charts directives into my application and everything works perfectly when initializing the data. However, I encountered an issue when reading the data from a JSON file and assigning it to the chart. The x-axis and y-axis are gener ...

The entered value in the <input> field is not valid

I am encountering an issue where the input value is auto-filled, but when I click the submit button, the input field value is not recognized unless I modify something in it, such as deleting and adding the last word to the first name. Is there a way to m ...

I am looking to implement a feature that will disable unchecked checkboxes based on certain conditions in a

Upon selection of an option from a dataset, an API call is triggered. The API response includes an object with a nested array, whose values are listed as checkboxes. Additionally, the API returns a key named choose(const name primaryMax) indicating the max ...

Morgan middleware in Express.js specifically targeting unsuccessful requests for logging purposes

Currently, I am facing an issue with my middleware setup in Express.js while using Morgan. The problem arises because Morgan is only logging requests that return error code 302 (redirected), which happens when my middleware encounters an error and redirect ...

What are the steps to develop an ElectronJS application that displays "Hello world!" in the console after a button click?

Can anyone offer a helping hand? From the depths of imagination to the realms never before conceived by humans. Check out this HTML snippet: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Hell ...

chai - anticipate an array including a JSON object with a specific key-value pair

Looking to utilize chai to verify if an array contains a JSON object with a specific key-value pair. Here is an example of my array: [{ path: '/products/setImage', message: 'hello', ... }, {...}] I want to confirm whether this array ...

"Steps to retrieve the button's ID when using the onClick event in Reactjs

Currently, I am working with Reactjs and Nextjs. I am utilizing functional components instead of classes. Within a loop, I have buttons and I am attempting to retrieve the id of the button when clicked using "onClick". Unfortunately, I am encountering th ...

Retrieve JSON data by making a POST request to a website's API

Can you help me retrieve Json data from a website API using JavaScript? I'm trying to fetch quotes from the following website: for my quotes generator page. While I have some understanding of making GET requests, it seems that this API requires POST ...

What is the best way to programmatically change the event tied to an element's click

<div id="filters"></div> <div id="available"> <span class="badge badge-pill" onclick="addFilter()">Label</span> </div> function addFilter(event) { document.getElementById("filters").appendChild(eve ...

How to send emails with attachments using WordPress?

Looking for assistance in sending emails with attachments using Wordpress. I am struggling and believe there might be something missing in my code. Any help would be greatly appreciated! :) Below is the code spread across two files: Name (required)<b ...

HTML embedded content is not appearing on the React webpage

I'm attempting to incorporate GoFundMe donation buttons into a React page, but unfortunately, they aren't displaying on the screen. const Donation = () => { return ( <div> <div className="gfm-embed" d ...

AngularJS search suggestions feature is malfunctioning

I've been attempting to run the following code on my computer, but I'm unable to achieve the desired result. Interestingly, when I ran the same code on JS Fiddler, it worked perfectly. Here is my index.html: <div ng-app="myApp" ng-controller ...

Fetching JSON array from servlet with AJAX

I have two JSON arrays in my servlet. I am trying to retrieve the values from the JSON arrays and display them on a JSP page using AJAX. Here is the code snippet: JSONArray htags = new JSONArray(); htags.add("#abc"); htags.add("#xyz"); ...

Python Hangman: Guess the Word

I'm currently dealing with a bug in one of my projects. The 'no' option works perfectly, however, every time I input 'yes', the following message pops up: TIME TO PLAY HANGMAN Do you want to play again (yes or no)? Below is the c ...

How To Access a View by Clicking in Ionic Framework

I have designed the main screen shown below. When each link is clicked, it should open the corresponding view. https://i.sstatic.net/H84jt.png Here is what I have created so far: Main Screen <body ng-app="starter"> <ion-pane> < ...

How to Add Functionality to Angular Apps Without Defining a Route

One unique aspect of my website is the navigation bar. It appears on some pages but not others, so I've created a controller specifically for it. Here's how the navigation bar markup looks: <html ng-app="myApp"> <head> <title& ...

Unraveling an AJAX response in JSON format using jQuery

I am a beginner in the world of Jquery and Ajax. I've crafted the code below to automatically populate a form with data after selecting an option from a combo box within a form, using guidance from this helpful post Autopopulate form based on selected ...

An error occurred as the Serverless Function timed out while attempting to load a dynamic route in Next.js version 13

I have a basic Next.js application with the following route structure: /contentA/ - Static - Initial load: 103 kB /contentA/[paramA]/groups - SSG - Initial load: 120 kB /contentB/[paramA]/[paramB]/[paramC] - SSR (client component) - Initial load: 103 kB ...