0
\$\begingroup\$

I have to parse a json object that can be a string, array, array of strings and array of object. I realised that it's not good from the beginning that one object can be many types, but I can't change the code from upstream so I'll have to deal it in my code instead. I'm building a pixel library for modern browser so I'm not using jQuery or lodash. I'm supporting most modern browser and IE >= 9

Here's the example of the data that can be returned

"author": {
 "@type": "Person",
 "name": "Author"
}

Or

"author":[{"@type":"Person","name":"Author"}]

Or

"author": 'Author'

Or

"author": ['Author', 'Author1']

And this is my code.

  let obj = {};
  try {
    const json = document.querySelector('div.json');
    if (json) {
      let disc = JSON.parse(json.innerHTML);
      let authors = disc.author;

      if (typeof authors !== 'undefined' && Array.isArray(authors) && authors.length > 0) {
        authors = authors.map((author) => {
          if (typeof author === 'object' && author.name) {
            return author.name;
          } else {
            return author;
          }
        });
      }

      if (typeof authors !== 'undefined' && !Array.isArray(authors) && typeof authors === 'object') {
        authors = [authors.name];
      }

      if (typeof authors !== 'undefined' && typeof authors === 'string') {
        authors = authors.split(',');
      }

      obj.cAu: authors.join(',');
    }
  } catch (e) { }

  return obj;

My question is, is there a better way to do this in a more efficient way?

\$\endgroup\$
  • \$\begingroup\$ Could you include the content "div.json" has in your html. We need to have your sample json to be able to review your code. \$\endgroup\$ – Siobhan Jul 22 '16 at 23:27
2
\$\begingroup\$

Personally I would have written the function as below. One thing that stood out that I noticed is that you are not returning anything in the catch statement of your try. So there is a certain 'ambiguity' as to what the function will return.

Here is my reasoning for the code style below:

  1. I expect the invoker to provide me with the JSON string that needs to data extracted from it, so that I can perform some immediate input validation. If the input is falsey I will return an empty string.

  2. I check whether the parsed result is an instance of an array (undefined or null will not pass this check)

  3. If it is an instance of an array I will check whether it is an array of objects, otherwise I will assume it is a string. I map these entries, and join them with a comma and return the result

  4. if the type is of an object (and not array since we already checked for that), I will return the name property of that object.

Feel free to wrap this in a try'catch but make sure you return something on the catch. I assume the invoker is expecting a string back.

function parseAuthor(authorString){
  if(!authorString){
    return '';
  }

  const authorObj = JSON.parse(authorString);

  if (typeof authorObj === 'string') {
    return authorObj;
  }

  if (authorObj instanceof Array) {
    entries = authorObj.map((a) => {
      if(typeof a === 'object' && a.name){
        return a.name;
      } else {
        return a;
      }
    });

    return entries.join(',');
  }

  if (typeof authorObj === 'object' && authorObj.name) {
    return authorObj.name;
  }

  return '';
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.