Search code examples
javascriptjsonserialization

Json.stringify() is ignoring a object property after xlsx.sheet_to_json


I'm using the SheetJs library to read an Excel file.

 const data = XLSX.utils.sheet_to_json(workbook.Sheets[sheet])

Which returns objects like this.

{webShop: 'AR_APPD-72642_RDS_Retailer_User', __EMPTY: '',
  webShop: ""
  __EMPTY: ""
  __EMPTY_2: "AR_APPD-72642_RDS_Retailer_User (Prod)"
  __EMPTY_3: "AR_APPD-72642_RDS_Retailer_User (Prod) "
  __EMPTY_4: "RtailerUI"
  __EMPTY_5: "RtailerUI"
  __rowNum__: 58

enter image description here

Ignoring the other properties.

The property rowNum is created by the sheet_to_json function and returns the Excel row Number of the Object.

I then use JSON.stringifyto create the JSON string of a single excel sheet. Which I string concatenate to a previous sheet.

this.convertedJson= this.convertedJson +JSON.stringify(data,undefined, 4);

Now the problem I'm encountering. After using .stringify() I get returned every single property the different rows have, except rowNum.

This is the part of the output String for the Object above.

{
        "WebShop": "AR_APPD-72642_RDS_RetailerUI_User",
        "__EMPTY": "",
        "__EMPTY_2": "AR RDS Retailer UI User (Prod)",
        "__EMPTY_3": "AR RDS Retailer UI User (Prod) ",
        "__EMPTY_4": "RtailerUI",
        "__EMPTY_5": "RtailerAI"
    }

I've found an older changelog of SheetJs, where I've noticed that the rowNum property was changed from enumerable to non-enumerable. Following up on that lead, apparently you cant serialize non-enumerable properties with .stringify(). Does anyone know a simple solution how I can still use .stringify() with non-enumerable properties. Or how I can change all rowNum properties of every object to enumerable?


Solution

  • As others have stated before, if the property is not enumerable it wont be picked by JSON.stringify. So you need to copy each object as @Keith says or redefine the property to enumerable as @Barmar states.

    I would like to add here, if you opt for redefine the property, and if the property is configurable

    Knowing beforehand the name of the property you can add a custom stringify function

    nonEnumStringify = (obj) => {
    const nonEnumObj = JSON.stringify(obj, (key, val) => {
        if (!key) {
            if (typeof val === 'object' && val.hasOwnProperty('__rowNum__')) {
                Object.defineProperty(val, '__rowNum__', {
                    value: val.__rowNum__,
                    enumerable: true,
                });
            }
        }
        return val;
    });
    return nonEnumObj;}
    

    And then simply call nonEnumStringify(data) instead of the standard JSON.stringify