2

I have some legacy code that returns nested stringified json as such:

"{ "value1": "name", "value2": "lastName", "value3": "{ \"subValue1\": \"\", \"subValue2\": null }" }"

and I am trying to write a parser function that would go into those nested objects, and parse them as well, however, I get a strange side effect where the parser does its job, but also adds extra values. Using example above it basically does this:

{
  0: "N",
  1: "O",
  value1: "name",
  value2: "NO",
  value3: {
    subValue1: "",
    subValue2: null,
  }
}

and I can't seem to debug it :/

Here is the parser in question:

const addValuesToObject = ({ object, keysArray, value }) => {
    for (let i = 0; i < keysArray.length; i++) {
       const lastKey = i === keysArray.length - 1;
       object = object[keysArray[i]] = object[keysArray[i]] || (lastKey ? value : {});
    }
    
    return object;
 };

 const isStringifiedObject = (value) => typeof value === "string" && value[0] === "{" && value[value.length - 1] === "}";

 const nestedJsonParser = (stringifiedObject) => {
        
    if (!stringifiedObject) return {};

    let newObject = {};

    const parser = (value, objectPath = []) => {
      const isStringified = isStringifiedObject(value);

      // if it's a stringified object, parse and add values;
      if (isStringified) {
        const newParsedObject = JSON.parse(value);
        const keys = Object.keys(newParsedObject);

        keys.forEach((key) => {
          parser(newParsedObject[key], [...objectPath, key]);
        });
      } else {
        const newEntry = addValuesToObject({ value, keysArray: objectPath, object: newObject });
        newObject = { ...newObject, ...newEntry };
      }
    };

    parser(stringifiedObject);

    return newObject;
  };

if anyone can help me to avoid the whole adding of "0": "Y" thing, it would be greatly appreciated.

Edit: I'm fine with isStringifiedObject being a little wonky as it is, I don't expect to get usable strings that start/end with {}

1 Answer 1

8

You can use JSON.parse with a "reviver" that recursively tries to parse every decoded string as json (and returns the argument as is if that fails):

function parseNested(str) {
    try {
        return JSON.parse(str, (_, val) => {
            if (typeof val === 'string')
                return parseNested(val)
            return val
        })
    } catch (exc) {
        return str
    }
}

// demo

obj = {
    'abc': 'def',
    'foo': 'bar',
    'nest1': JSON.stringify({deep1: 123}),
    'nest2': JSON.stringify({deep2: JSON.stringify({deep3: ['something', 'else']})}),
}

weird = JSON.stringify(obj)
console.log(weird)
console.log(parseNested(weird))

Sign up to request clarification or add additional context in comments.

3 Comments

Elegant solution and works like a charm. Thank you very much. I have much more to learn I see, instead of logic hammering the parser like a Neanderthal
))) glad to hear it helped.
Fantastic; thx!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.