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?
-
\$\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\$Tolani– Tolani2016年07月22日 23:27:55 +00:00Commented Jul 22, 2016 at 23:27
1 Answer 1
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:
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.
I check whether the parsed result is an instance of an array (undefined or null will not pass this check)
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
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 '';
}